diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime/r3 | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime/r3')
143 files changed, 8953 insertions, 3029 deletions
diff --git a/src/VBox/Runtime/r3/alloc-ef-cpp.cpp b/src/VBox/Runtime/r3/alloc-ef-cpp.cpp index 7aa12880..eb8614e3 100644 --- a/src/VBox/Runtime/r3/alloc-ef-cpp.cpp +++ b/src/VBox/Runtime/r3/alloc-ef-cpp.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/alloc-ef.cpp b/src/VBox/Runtime/r3/alloc-ef.cpp index 16892e29..570800be 100644 --- a/src/VBox/Runtime/r3/alloc-ef.cpp +++ b/src/VBox/Runtime/r3/alloc-ef.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/alloc.cpp b/src/VBox/Runtime/r3/alloc.cpp index 94889c10..98892aaa 100644 --- a/src/VBox/Runtime/r3/alloc.cpp +++ b/src/VBox/Runtime/r3/alloc.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -39,6 +39,10 @@ # undef RTMEMALLOC_USE_TRACKER #endif +#if defined(RTMEMALLOC_USE_TRACKER) && defined(RTALLOC_USE_EFENCE) +# error "Cannot define both RTMEMALLOC_USE_TRACKER and RTALLOC_USE_EFENCE!" +#endif + /******************************************************************************* * Header Files * diff --git a/src/VBox/Runtime/r3/allocex.cpp b/src/VBox/Runtime/r3/allocex.cpp new file mode 100644 index 00000000..c1bd6a40 --- /dev/null +++ b/src/VBox/Runtime/r3/allocex.cpp @@ -0,0 +1,126 @@ +/* $Id: allocex.cpp $ */ +/** @file + * IPRT - Memory Allocation, Extended Alloc and Free Functions for Ring-3, posix. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define RTMEM_NO_WRAP_TO_EF_APIS +#include <iprt/mem.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/string.h> +#include "internal/magics.h" +#include "allocex.h" + + +RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW +{ + /* + * Validate and adjust input. + */ + AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); + AssertReturn(cb > 0, VERR_INVALID_PARAMETER); + AssertReturn(RT_IS_POWER_OF_TWO(cbAlignment), VERR_INVALID_PARAMETER); + AssertMsgReturn(cbAlignment <= sizeof(void *), ("%zu (%#x)\n", cbAlignment, cbAlignment), VERR_UNSUPPORTED_ALIGNMENT); + + if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX) + return VERR_NOT_SUPPORTED; + + /* + * Align the request. + */ + size_t cbAligned = cb; + if (cbAlignment) + cbAligned = RT_ALIGN_Z(cb, cbAlignment); + else + cbAligned = RT_ALIGN_Z(cb, sizeof(uint64_t)); + AssertMsgReturn(cbAligned >= cb && cbAligned <= ~(size_t)0, ("cbAligned=%#zx cb=%#zx", cbAligned, cb), + VERR_INVALID_PARAMETER); + + /* + * Allocate the requested memory. + */ + void *pv; + if (fFlags & (RTMEMALLOCEX_FLAGS_16BIT_REACH | RTMEMALLOCEX_FLAGS_32BIT_REACH)) + { + int rc; + if (fFlags & RTMEMALLOCEX_FLAGS_16BIT_REACH) + rc = rtMemAllocEx16BitReach(cbAligned + sizeof(RTMEMHDRR3), fFlags, &pv); + else + rc = rtMemAllocEx32BitReach(cbAligned + sizeof(RTMEMHDRR3), fFlags, &pv); + if (RT_FAILURE(rc)) + return rc; + } + else if (fFlags & RTMEMALLOCEX_FLAGS_EXEC) + { + pv = RTMemExecAlloc(cbAligned + sizeof(RTMEMHDRR3)); + if ((fFlags & RTMEMALLOCEX_FLAGS_ZEROED) && pv) + RT_BZERO(pv, cbAligned + sizeof(RTMEMHDRR3)); + } + else if (fFlags & RTMEMALLOCEX_FLAGS_ZEROED) + pv = RTMemAllocZ(cbAligned + sizeof(RTMEMHDRR3)); + else + pv = RTMemAlloc(cbAligned + sizeof(RTMEMHDRR3)); + if (!pv) + return VERR_NO_MEMORY; + + /* + * Fill in the header and return. + */ + PRTMEMHDRR3 pHdr = (PRTMEMHDRR3)pv; + pHdr->u32Magic = RTMEMHDR_MAGIC; + pHdr->fFlags = fFlags; + pHdr->cb = (uint32_t)cbAligned; + pHdr->cbReq = (uint32_t)cb; + + *ppv = pHdr + 1; + return VINF_SUCCESS; +} +RT_EXPORT_SYMBOL(RTMemAllocExTag); + + +RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW +{ + if (!pv) + return; + AssertPtr(pv); + + PRTMEMHDRR3 pHdr = (PRTMEMHDRR3)pv - 1; + AssertMsg(pHdr->u32Magic == RTMEMHDR_MAGIC, ("pHdr->u32Magic=%RX32 pv=%p cb=%#x\n", pHdr->u32Magic, pv, cb)); + pHdr->u32Magic = RTMEMHDR_MAGIC_DEAD; + Assert(pHdr->cbReq == cb); + + if (pHdr->fFlags & (RTMEMALLOCEX_FLAGS_16BIT_REACH | RTMEMALLOCEX_FLAGS_32BIT_REACH)) + rtMemFreeExYyBitReach(pHdr, pHdr->cb + sizeof(*pHdr), pHdr->fFlags); + else if (pHdr->fFlags & RTMEMALLOCEX_FLAGS_EXEC) + RTMemExecFree(pHdr, pHdr->cb + sizeof(*pHdr)); + else + RTMemFree(pHdr); +} +RT_EXPORT_SYMBOL(RTMemFreeEx); + diff --git a/src/VBox/Runtime/r3/allocex.h b/src/VBox/Runtime/r3/allocex.h new file mode 100644 index 00000000..2724335c --- /dev/null +++ b/src/VBox/Runtime/r3/allocex.h @@ -0,0 +1,84 @@ +/* $Id: allocex.h $ */ +/** @file + * IPRT - Memory Allocation, Extended Alloc and Free Functions for Ring-3. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#ifndef ___r3_allocex_h +#define ___r3_allocex_h + +#include <iprt/types.h> + +/** + * Heading for extended memory allocations in ring-3. + */ +typedef struct RTMEMHDRR3 +{ + /** Magic (RTMEMHDR_MAGIC). */ + uint32_t u32Magic; + /** Block flags (RTMEMALLOCEX_FLAGS_*). */ + uint32_t fFlags; + /** The actual size of the block, header not included. */ + uint32_t cb; + /** The requested allocation size. */ + uint32_t cbReq; +} RTMEMHDRR3; +/** Pointer to a ring-3 extended memory header. */ +typedef RTMEMHDRR3 *PRTMEMHDRR3; + + +/** + * Allocate memory in below 64KB. + * + * @returns IPRT status code. + * @param cbAlloc Number of bytes to allocate (including the + * header if the caller needs one). + * @param fFlags Allocation flags. + * @param ppv Where to return the pointer to the memory. + */ +DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv); + +/** + * Allocate memory in below 4GB. + * + * @returns IPRT status code. + * @param cbAlloc Number of bytes to allocate (including the + * header if the caller needs one). + * @param fFlags Allocation flags. + * @param ppv Where to return the pointer to the memory. + */ +DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv); + + +/** + * Frees memory allocated by rtMemAllocEx16BitReach and rtMemAllocEx32BitReach. + * + * @param pv Start of allocation. + * @param cb Allocation size. + * @param fFlags Allocation flags. + */ +DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags); + +#endif + diff --git a/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp index 2b033b2f..aae99908 100644 --- a/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp +++ b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -28,10 +28,18 @@ * Header Files * *******************************************************************************/ #include <iprt/path.h> -#include <iprt/err.h> +#include "internal/iprt.h" + #include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/err.h> + +#include <NSSystemDirectories.h> +#include <sys/syslimits.h> +#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS +# include <CoreServices/CoreServices.h> +#endif -#include <CoreServices/CoreServices.h> RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath) { @@ -41,15 +49,50 @@ RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath) AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(cchPath, VERR_INVALID_PARAMETER); - FSRef ref; - OSErr err = FSFindFolder(kOnAppropriateDisk, kDocumentsFolderType, false /* createFolder */, &ref); - if (err != noErr) - return VERR_PATH_NOT_FOUND; + /* + * Try NSSystemDirectories first since that works for directories that doesn't exist. + */ + int rc = VERR_PATH_NOT_FOUND; + NSSearchPathEnumerationState EnmState = NSStartSearchPathEnumeration(NSDocumentDirectory, NSUserDomainMask); + if (EnmState != 0) + { + char szTmp[PATH_MAX]; + szTmp[0] = szTmp[PATH_MAX - 1] = '\0'; + EnmState = NSGetNextSearchPathEnumeration(EnmState, szTmp); + if (EnmState != 0) + { + size_t cchTmp = strlen(szTmp); + if (cchTmp >= cchPath) + return VERR_BUFFER_OVERFLOW; - err = FSRefMakePath(&ref, (UInt8*)pszPath, cchPath); - if (err != noErr) - return VERR_PATH_NOT_FOUND; + if (szTmp[0] == '~' && szTmp[1] == '/') + { + /* Expand tilde. */ + rc = RTPathUserHome(pszPath, cchPath - cchTmp + 2); + if (RT_FAILURE(rc)) + return rc; + rc = RTPathAppend(pszPath, cchPath, &szTmp[2]); + } + else + rc = RTStrCopy(pszPath, cchPath, szTmp); + return rc; + } + } - return VINF_SUCCESS; +#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS + /* + * Fall back on FSFindFolder in case the above should fail... + */ + FSRef ref; + OSErr err = FSFindFolder(kOnAppropriateDisk, kDocumentsFolderType, false /* createFolder */, &ref); + if (err == noErr) + { + err = FSRefMakePath(&ref, (UInt8*)pszPath, cchPath); + if (err == noErr) + return VINF_SUCCESS; + } +#endif + Assert(RT_FAILURE_NP(rc)); + return rc; } diff --git a/src/VBox/Runtime/r3/darwin/mp-darwin.cpp b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp index 9942686a..bfdeb0d4 100644 --- a/src/VBox/Runtime/r3/darwin/mp-darwin.cpp +++ b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -46,18 +46,63 @@ /** - * Internal worker that determines the max possible CPU count. + * Internal worker that determines the max possible logical CPU count (hyperthreads). * * @returns Max cpus. */ -static RTCPUID rtMpDarwinMaxCpus(void) +static RTCPUID rtMpDarwinMaxLogicalCpus(void) { - int aiMib[2]; - aiMib[0] = CTL_HW; - aiMib[1] = HW_NCPU; int cCpus = -1; size_t cb = sizeof(cCpus); - int rc = sysctl(aiMib, RT_ELEMENTS(aiMib), &cCpus, &cb, NULL, 0); + int rc = sysctlbyname("hw.logicalcpu_max", &cCpus, &cb, NULL, 0); + if (rc != -1 && cCpus >= 1) + return cCpus; + AssertFailed(); + return 1; +} + +/** + * Internal worker that determines the max possible physical core count. + * + * @returns Max cpus. + */ +static RTCPUID rtMpDarwinMaxPhysicalCpus(void) +{ + int cCpus = -1; + size_t cb = sizeof(cCpus); + int rc = sysctlbyname("hw.physicalcpu_max", &cCpus, &cb, NULL, 0); + if (rc != -1 && cCpus >= 1) + return cCpus; + AssertFailed(); + return 1; +} + +/** + * Internal worker that determines the current number of logical CPUs (hyperthreads). + * + * @returns Max cpus. + */ +static RTCPUID rtMpDarwinOnlineLogicalCpus(void) +{ + int cCpus = -1; + size_t cb = sizeof(cCpus); + int rc = sysctlbyname("hw.logicalcpu", &cCpus, &cb, NULL, 0); + if (rc != -1 && cCpus >= 1) + return cCpus; + AssertFailed(); + return 1; +} + +/** + * Internal worker that determines the current number of physical CPUs. + * + * @returns Max cpus. + */ +static RTCPUID rtMpDarwinOnlinePhysicalCpus(void) +{ + int cCpus = -1; + size_t cb = sizeof(cCpus); + int rc = sysctlbyname("hw.physicalcpu", &cCpus, &cb, NULL, 0); if (rc != -1 && cCpus >= 1) return cCpus; AssertFailed(); @@ -69,19 +114,19 @@ static RTCPUID rtMpDarwinMaxCpus(void) RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu) { - return idCpu < RTCPUSET_MAX_CPUS && idCpu < rtMpDarwinMaxCpus() ? idCpu : -1; + return idCpu < RTCPUSET_MAX_CPUS && idCpu < rtMpDarwinMaxLogicalCpus() ? idCpu : -1; } RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu) { - return (unsigned)iCpu < rtMpDarwinMaxCpus() ? iCpu : NIL_RTCPUID; + return (unsigned)iCpu < rtMpDarwinMaxLogicalCpus() ? iCpu : NIL_RTCPUID; } RTDECL(RTCPUID) RTMpGetMaxCpuId(void) { - return rtMpDarwinMaxCpus() - 1; + return rtMpDarwinMaxLogicalCpus() - 1; } @@ -97,7 +142,7 @@ RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu) kern_return_t krc = host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO, &nCpus, (processor_info_array_t*)&pinfo, &count); AssertReturn (krc == KERN_SUCCESS, true); - bool isOnline = idCpu < nCpus ? pinfo[idCpu].running : true; + bool isOnline = idCpu < nCpus ? pinfo[idCpu].running : false; vm_deallocate(mach_task_self(), (vm_address_t)pinfo, count * sizeof(*pinfo)); return isOnline; #endif @@ -107,19 +152,19 @@ RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu) RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu) { return idCpu != NIL_RTCPUID - && idCpu < rtMpDarwinMaxCpus(); + && idCpu < rtMpDarwinMaxLogicalCpus(); } RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) { #if 0 - RTCPUID cCpus = rtMpDarwinMaxCpus(); + RTCPUID cCpus = rtMpDarwinMaxLogicalCpus(); return RTCpuSetFromU64(RT_BIT_64(cCpus) - 1); #else RTCpuSetEmpty(pSet); - RTCPUID cMax = rtMpDarwinMaxCpus(); + RTCPUID cMax = rtMpDarwinMaxLogicalCpus(); for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) if (RTMpIsCpuPossible(idCpu)) RTCpuSetAdd(pSet, idCpu); @@ -130,7 +175,13 @@ RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) RTDECL(RTCPUID) RTMpGetCount(void) { - return rtMpDarwinMaxCpus(); + return rtMpDarwinMaxLogicalCpus(); +} + + +RTDECL(RTCPUID) RTMpGetCoreCount(void) +{ + return rtMpDarwinMaxPhysicalCpus(); } @@ -140,7 +191,7 @@ RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) return RTMpGetSet(pSet); #else RTCpuSetEmpty(pSet); - RTCPUID cMax = rtMpDarwinMaxCpus(); + RTCPUID cMax = rtMpDarwinMaxLogicalCpus(); for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) if (RTMpIsCpuOnline(idCpu)) RTCpuSetAdd(pSet, idCpu); diff --git a/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp index 103e70b4..922bd41e 100644 --- a/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp +++ b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -32,6 +32,9 @@ # include <mach-o/dyld.h> #endif +#include <stdlib.h> +#include <limits.h> +#include <errno.h> #include <iprt/string.h> #include <iprt/assert.h> #include <iprt/err.h> @@ -48,7 +51,13 @@ DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath) const char *pszImageName = _dyld_get_image_name(0); AssertReturn(pszImageName, VERR_INTERNAL_ERROR); - int rc = rtPathFromNativeCopy(pszPath, cchPath, pszImageName, NULL); + char szTmpPath[PATH_MAX + 1]; + const char *psz = realpath(pszImageName, szTmpPath); + int rc; + if (psz) + rc = rtPathFromNativeCopy(pszPath, cchPath, szTmpPath, NULL); + else + rc = RTErrConvertFromErrno(errno); AssertMsgRCReturn(rc, ("rc=%Rrc pszLink=\"%s\"\nhex: %.*Rhxs\n", rc, pszPath, strlen(pszImageName), pszPath), rc); return VINF_SUCCESS; diff --git a/src/VBox/Runtime/r3/darwin/sched-darwin.cpp b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp index ad47cdbb..3879db8c 100644 --- a/src/VBox/Runtime/r3/darwin/sched-darwin.cpp +++ b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/darwin/time-darwin.cpp b/src/VBox/Runtime/r3/darwin/time-darwin.cpp index 38878c63..a737d01b 100644 --- a/src/VBox/Runtime/r3/darwin/time-darwin.cpp +++ b/src/VBox/Runtime/r3/darwin/time-darwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/dir.cpp b/src/VBox/Runtime/r3/dir.cpp index 16f2577e..1cfa50d7 100644 --- a/src/VBox/Runtime/r3/dir.cpp +++ b/src/VBox/Runtime/r3/dir.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,14 +29,6 @@ * Header Files * *******************************************************************************/ #define LOG_GROUP RTLOGGROUP_DIR -#ifdef RT_OS_WINDOWS /* PORTME: Assumes everyone else is using dir-posix.cpp */ -# include <Windows.h> -#else -# include <dirent.h> -# include <unistd.h> -# include <limits.h> -#endif - #include <iprt/dir.h> #include "internal/iprt.h" @@ -49,6 +41,7 @@ #include <iprt/path.h> #include <iprt/string.h> #include <iprt/uni.h> +#define RTDIR_AGNOSTIC #include "internal/dir.h" #include "internal/path.h" @@ -533,7 +526,7 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi if (!pszFilter) { cbFilter = cucFilter0 = 0; - rc = RTPathReal(pszPath, szRealPath, sizeof(szRealPath) - 1); + rc = RTPathAbs(pszPath, szRealPath, sizeof(szRealPath) - 1); } else { @@ -547,7 +540,7 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi if (!pszTmp) return VERR_NO_MEMORY; pszTmp[pszFilter - pszPath] = '\0'; - rc = RTPathReal(pszTmp, szRealPath, sizeof(szRealPath) - 1); + rc = RTPathAbs(pszTmp, szRealPath, sizeof(szRealPath) - 1); RTStrFree(pszTmp); } else @@ -570,34 +563,19 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi * The posix definition of Data.d_name allows it to be < NAME_MAX + 1, * thus the horrible ugliness here. Solaris uses d_name[1] for instance. */ -#ifndef RT_OS_WINDOWS - long cbNameMax = pathconf(szRealPath, _PC_NAME_MAX); -# ifdef NAME_MAX - if (cbNameMax < NAME_MAX) /* This is plain paranoia, but it doesn't hurt. */ - cbNameMax = NAME_MAX; -# endif -# ifdef _XOPEN_NAME_MAX - if (cbNameMax < _XOPEN_NAME_MAX) /* Ditto. */ - cbNameMax = _XOPEN_NAME_MAX; -# endif - size_t cbDir = RT_OFFSETOF(RTDIR, Data.d_name[cbNameMax + 1]); - if (cbDir < sizeof(RTDIR)) /* Ditto. */ - cbDir = sizeof(RTDIR); - cbDir = RT_ALIGN_Z(cbDir, 8); -#else - size_t cbDir = sizeof(RTDIR); -#endif + size_t cbDir = rtDirNativeGetStructSize(szRealPath); size_t const cbAllocated = cbDir + cucFilter0 * sizeof(RTUNICP) + cbFilter + cchRealPath + 1 + 4; - PRTDIR pDir = (PRTDIR)RTMemAlloc(cbAllocated); + PRTDIR pDir = (PRTDIR)RTMemAllocZ(cbAllocated); if (!pDir) return VERR_NO_MEMORY; uint8_t *pb = (uint8_t *)pDir + cbDir; /* initialize it */ pDir->u32Magic = RTDIR_MAGIC; + pDir->cbSelf = cbDir; if (cbFilter) { pDir->puszFilter = (PRTUNICP)pb; @@ -638,9 +616,6 @@ static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFi pDir->fDataUnread = false; pDir->pszName = NULL; pDir->cchName = 0; -#ifndef RT_OS_WINDOWS - pDir->cbMaxName = cbDir - RT_OFFSETOF(RTDIR, Data.d_name); -#endif /* * Hand it over to the native part. @@ -730,3 +705,70 @@ RTDECL(int) RTDirFlushParent(const char *pszChild) return rc; } + +RTDECL(int) RTDirQueryUnknownTypeEx(const char *pszComposedName, bool fFollowSymlinks, + RTDIRENTRYTYPE *penmType, PRTFSOBJINFO pObjInfo) +{ + int rc = RTPathQueryInfoEx(pszComposedName, pObjInfo, RTFSOBJATTRADD_NOTHING, + fFollowSymlinks ? RTPATH_F_FOLLOW_LINK : RTPATH_F_ON_LINK); + if (RT_FAILURE(rc)) + return rc; + + if (RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_DIRECTORY; + else if (RTFS_IS_FILE(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_FILE; + else if (RTFS_IS_SYMLINK(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_SYMLINK; + else if (RTFS_IS_FIFO(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_FIFO; + else if (RTFS_IS_DEV_CHAR(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_DEV_CHAR; + else if (RTFS_IS_DEV_BLOCK(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_DEV_BLOCK; + else if (RTFS_IS_SOCKET(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_SOCKET; + else if (RTFS_IS_WHITEOUT(pObjInfo->Attr.fMode)) + *penmType = RTDIRENTRYTYPE_WHITEOUT; + else + *penmType = RTDIRENTRYTYPE_UNKNOWN; + + return VINF_SUCCESS; +} + + +RTDECL(int) RTDirQueryUnknownType(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType) +{ + if ( *penmType != RTDIRENTRYTYPE_UNKNOWN + && ( !fFollowSymlinks + || *penmType != RTDIRENTRYTYPE_SYMLINK)) + return VINF_SUCCESS; + + RTFSOBJINFO ObjInfo; + return RTDirQueryUnknownTypeEx(pszComposedName, fFollowSymlinks, penmType, &ObjInfo); +} + + +RTDECL(bool) RTDirEntryIsStdDotLink(PRTDIRENTRY pDirEntry) +{ + if (pDirEntry->szName[0] != '.') + return false; + if (pDirEntry->cbName == 1) + return true; + if (pDirEntry->cbName != 2) + return false; + return pDirEntry->szName[1] == '.'; +} + + +RTDECL(bool) RTDirEntryExIsStdDotLink(PCRTDIRENTRYEX pDirEntryEx) +{ + if (pDirEntryEx->szName[0] != '.') + return false; + if (pDirEntryEx->cbName == 1) + return true; + if (pDirEntryEx->cbName != 2) + return false; + return pDirEntryEx->szName[1] == '.'; +} + diff --git a/src/VBox/Runtime/r3/dir2.cpp b/src/VBox/Runtime/r3/dir2.cpp index bec029de..f01f42c1 100644 --- a/src/VBox/Runtime/r3/dir2.cpp +++ b/src/VBox/Runtime/r3/dir2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/fileio.cpp b/src/VBox/Runtime/r3/fileio.cpp index 5b4e8873..fd1a2898 100644 --- a/src/VBox/Runtime/r3/fileio.cpp +++ b/src/VBox/Runtime/r3/fileio.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -208,6 +208,49 @@ RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRea /** + * Read bytes from a file at a given offset into a S/G buffer. + * This function may modify the file position. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to read. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read. + * If NULL an error will be returned for a partial read. + */ +RTR3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead) +{ + int rc = VINF_SUCCESS; + size_t cbRead = 0; + + while (cbToRead) + { + size_t cbThisRead = 0; + size_t cbBuf = cbToRead; + void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf); + + rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL); + if (RT_SUCCESS(rc)) + cbRead += cbThisRead; + + if ( RT_FAILURE(rc) + || ( cbThisRead < cbBuf + && pcbRead)) + break; + + cbToRead -= cbBuf; + off += cbBuf; + } + + if (pcbRead) + *pcbRead = cbRead; + + return rc; +} + + +/** * Write bytes to a file at a given offset. * This function may modify the file position. * @@ -229,6 +272,49 @@ RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t /** + * Write bytes from a S/G buffer to a file at a given offset. + * This function may modify the file position. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to write. + * @param pSgBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + */ +RTR3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten) +{ + int rc = VINF_SUCCESS; + size_t cbWritten = 0; + + while (cbToWrite) + { + size_t cbThisWritten = 0; + size_t cbBuf = cbToWrite; + void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf); + + rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL); + if (RT_SUCCESS(rc)) + cbWritten += cbThisWritten; + + if ( RT_FAILURE(rc) + || ( cbThisWritten < cbBuf + && pcbWritten)) + break; + + cbToWrite -= cbBuf; + off += cbBuf; + } + + if (pcbWritten) + *pcbWritten = cbWritten; + + return rc; +} + + +/** * Gets the current file position. * * @returns File offset. diff --git a/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp b/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp index 1d47c759..b5ddfcca 100644 --- a/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp +++ b/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -66,6 +66,8 @@ typedef struct RTFILEAIOCTXINTERNAL volatile bool fWokenUp; /** Flag whether the thread is currently waiting in the syscall. */ volatile bool fWaiting; + /** Flags given during creation. */ + uint32_t fFlags; /** Magic value (RTFILEAIOCTX_MAGIC). */ uint32_t u32Magic; } RTFILEAIOCTXINTERNAL; @@ -299,11 +301,13 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered) return pReqInt->Rc; } -RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags) { int rc = VINF_SUCCESS; PRTFILEAIOCTXINTERNAL pCtxInt; AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL)); if (RT_UNLIKELY(!pCtxInt)) @@ -313,6 +317,7 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) pCtxInt->iKQueue = kqueue(); if (RT_LIKELY(pCtxInt->iKQueue > 0)) { + pCtxInt->fFlags = fFlags; pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; *phAioCtx = (RTFILEAIOCTX)pCtxInt; } @@ -498,7 +503,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER); AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE); - if (RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0)) + if ( RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0) + && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS)) return VERR_FILE_AIO_NO_REQUEST; /* diff --git a/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp b/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp index 8296025b..8475dd04 100644 --- a/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp +++ b/src/VBox/Runtime/r3/freebsd/mp-freebsd.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp b/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp index 55112775..216c1004 100644 --- a/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp +++ b/src/VBox/Runtime/r3/freebsd/rtProcInitExePath-freebsd.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/fs.cpp b/src/VBox/Runtime/r3/fs.cpp index dac1a5cc..b79e43d2 100644 --- a/src/VBox/Runtime/r3/fs.cpp +++ b/src/VBox/Runtime/r3/fs.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -205,6 +205,7 @@ RTDECL(const char *) RTFsTypeName(RTFSTYPE enmType) case RTFSTYPE_SYSFS: return "sysfs"; case RTFSTYPE_PROC: return "proc"; case RTFSTYPE_OCFS2: return "ocfs2"; + case RTFSTYPE_BTRFS: return "btrfs"; case RTFSTYPE_NTFS: return "ntfs"; case RTFSTYPE_FAT: return "fat"; diff --git a/src/VBox/Runtime/r3/os2/poll-os2.cpp b/src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp index 890cdc8c..dd1dea61 100644 --- a/src/VBox/Runtime/r3/os2/poll-os2.cpp +++ b/src/VBox/Runtime/r3/generic/allocex-r3-generic.cpp @@ -1,10 +1,10 @@ -/* $Id: poll-os2.cpp $ */ +/* $Id: allocex-r3-generic.cpp $ */ /** @file - * IPRT - Polling I/O Handles, OS/2 Implementation. + * IPRT - Memory Allocation, Extended Alloc Workers, generic. */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -28,58 +28,30 @@ /******************************************************************************* * Header Files * *******************************************************************************/ -#include <iprt/poll.h> +#define RTMEM_NO_WRAP_TO_EF_APIS +#include <iprt/mem.h> #include "internal/iprt.h" #include <iprt/assert.h> #include <iprt/err.h> -#include "internal/magics.h" +#include "../allocex.h" -RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - return VERR_NOT_IMPLEMENTED; -} - - -RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - return VERR_NOT_IMPLEMENTED; -} - - -RTDECL(int) RTPollSetCreate(PRTPOLLSET hPollSet) -{ - return VERR_NOT_IMPLEMENTED; -} - - -RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet) -{ - return VERR_NOT_IMPLEMENTED; -} - - -RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id) -{ - return VERR_NOT_IMPLEMENTED; -} - -RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id) +DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) { - return VERR_NOT_IMPLEMENTED; + return VERR_NOT_SUPPORTED; } -RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) +DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) { - return VERR_NOT_IMPLEMENTED; + return VERR_NOT_SUPPORTED; } -RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet) +DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags) { - return UINT32_MAX; + AssertFailed(); } diff --git a/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp b/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp index 1c0e4603..e6edca4f 100644 --- a/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp +++ b/src/VBox/Runtime/r3/generic/semspinmutex-r3-generic.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp b/src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp new file mode 100644 index 00000000..7a41e9f1 --- /dev/null +++ b/src/VBox/Runtime/r3/haiku/rtProcInitExePath-haiku.cpp @@ -0,0 +1,60 @@ +/* $Id: rtProcInitExePath-haiku.cpp $ */ +/** @file + * IPRT - rtProcInitName, Haiku. + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_PROCESS +#ifdef RT_OS_HAIKU +# include <image.h> +#endif + +#include <iprt/string.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/path.h> +#include "internal/process.h" +#include "internal/path.h" + + +DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath) +{ + image_info ImageInfo; + int32 Cookie = 0; + status_t status; + + /* + * Query the image name from the OS, convert and return it. + */ + status = get_next_image_info(0, &Cookie, &ImageInfo); + AssertReturn((status == B_OK), VERR_INTERNAL_ERROR); + + int rc = rtPathFromNativeCopy(pszPath, MIN(cchPath, MAXPATHLEN), ImageInfo.name, NULL); + AssertMsgRCReturn(rc, ("rc=%Rrc pszLink=\"%s\"\nhex: %.*Rhxs\n", rc, pszPath, MIN(cchPath, MAXPATHLEN), pszPath), rc); + + return VINF_SUCCESS; +} + diff --git a/src/VBox/Runtime/r3/haiku/time-haiku.cpp b/src/VBox/Runtime/r3/haiku/time-haiku.cpp new file mode 100644 index 00000000..269b4b2c --- /dev/null +++ b/src/VBox/Runtime/r3/haiku/time-haiku.cpp @@ -0,0 +1,84 @@ +/* $Id: time-haiku.cpp $ */ +/** @file + * IPRT - Time, Haiku. + */ + +/* + * Copyright (C) 2012-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_TIME +#define RTTIME_INCL_TIMEVAL +#include <sys/time.h> +#include <time.h> +#include <unistd.h> + +#include <OS.h> + +#include <iprt/time.h> +#include <iprt/err.h> +#include "internal/time.h" + + +DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void) +{ + return (uint64_t)system_time() * 1000; +} + + +/** + * Gets the current nanosecond timestamp. + * + * This differs from RTTimeNanoTS in that it will use system APIs and not do any + * resolution or performance optimizations. + * + * @returns nanosecond timestamp. + */ +RTDECL(uint64_t) RTTimeSystemNanoTS(void) +{ + return rtTimeGetSystemNanoTS(); +} + + +/** + * Gets the current millisecond timestamp. + * + * This differs from RTTimeNanoTS in that it will use system APIs and not do any + * resolution or performance optimizations. + * + * @returns millisecond timestamp. + */ +RTDECL(uint64_t) RTTimeSystemMilliTS(void) +{ + return rtTimeGetSystemNanoTS() / 1000000; +} + + +RTDECL(int) RTTimeSet(PCRTTIMESPEC pTime) +{ + struct timeval tv; + RTTimeSpecGetTimeval(pTime, &tv); + set_real_time_clock(tv.tv_sec); + return VINF_SUCCESS; +} diff --git a/src/VBox/Runtime/r3/init.cpp b/src/VBox/Runtime/r3/init.cpp index 8c3699d1..1f680bf2 100644 --- a/src/VBox/Runtime/r3/init.cpp +++ b/src/VBox/Runtime/r3/init.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -66,11 +66,11 @@ #endif #include <stdlib.h> +#include "init.h" #include "internal/alignmentchecks.h" #include "internal/path.h" #include "internal/process.h" #include "internal/thread.h" -#include "internal/thread.h" #include "internal/time.h" @@ -92,6 +92,9 @@ DECLHIDDEN(size_t) g_cchrtProcDir; /** The offset of the process name into g_szrtProcExePath. */ DECLHIDDEN(size_t) g_offrtProcName; +/** The IPRT init flags. */ +static uint32_t g_fInitFlags; + /** The argument count of the program. */ static int g_crtArgs = -1; /** The arguments of the program (UTF-8). This is "leaked". */ @@ -139,6 +142,15 @@ RTDATADECL(bool) g_fRTAlignmentChecks = false; #endif +#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_HAIKU) \ + || defined(RT_OS_LINUX) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS) /** @todo add host init hooks everywhere. */ +/* Stubs */ +DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags) { return VINF_SUCCESS; } +DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags) { return VINF_SUCCESS; } +DECLHIDDEN(void) rtR3InitNativeObtrusive(void) { } +#endif + + /** * atexit callback. * @@ -228,7 +240,7 @@ static int rtR3InitProgramPath(const char *pszProgramPath) * Parse the name. */ ssize_t offName; - g_cchrtProcExePath = RTPathParse(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL); + g_cchrtProcExePath = RTPathParseSimple(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL); g_offrtProcName = offName; return VINF_SUCCESS; } @@ -265,31 +277,74 @@ static int rtR3InitArgv(uint32_t fFlags, int cArgs, char ***ppapszArgs) return VINF_SUCCESS; } - /* - * Convert the arguments. - */ - char **papszArgs = (char **)RTMemAllocZ((cArgs + 1) * sizeof(char *)); - if (!papszArgs) - return VERR_NO_MEMORY; - - for (int i = 0; i < cArgs; i++) + if (!(fFlags & RTR3INIT_FLAGS_UTF8_ARGV)) { - int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]); - if (RT_FAILURE(rc)) + /* + * Convert the arguments. + */ + char **papszArgs = (char **)RTMemAllocZ((cArgs + 1) * sizeof(char *)); + if (!papszArgs) + return VERR_NO_MEMORY; + +#ifdef RT_OS_WINDOWS + /* HACK ALERT! Try convert from unicode versions if possible. + Unfortunately for us, __wargv is only initialized if we have a + unicode main function. So, we have to use CommandLineToArgvW to get + something similar. It should do the same conversion... :-) */ + int cArgsW = -1; + PWSTR *papwszArgs = NULL; + if ( papszOrgArgs == __argv + && cArgs == __argc + && (papwszArgs = CommandLineToArgvW(GetCommandLineW(), &cArgsW)) != NULL ) { - while (i--) - RTStrFree(papszArgs[i]); - RTMemFree(papszArgs); - return rc; + AssertMsg(cArgsW == cArgs, ("%d vs %d\n", cArgsW, cArgs)); + for (int i = 0; i < cArgs; i++) + { + int rc = RTUtf16ToUtf8(papwszArgs[i], &papszArgs[i]); + if (RT_FAILURE(rc)) + { + while (i--) + RTStrFree(papszArgs[i]); + RTMemFree(papszArgs); + LocalFree(papwszArgs); + return rc; + } + } + LocalFree(papwszArgs); + } + else +#endif + { + for (int i = 0; i < cArgs; i++) + { + int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]); + if (RT_FAILURE(rc)) + { + while (i--) + RTStrFree(papszArgs[i]); + RTMemFree(papszArgs); + return rc; + } + } } - } - papszArgs[cArgs] = NULL; - g_papszrtOrgArgs = papszOrgArgs; - g_papszrtArgs = papszArgs; - g_crtArgs = cArgs; + papszArgs[cArgs] = NULL; - *ppapszArgs = papszArgs; + g_papszrtOrgArgs = papszOrgArgs; + g_papszrtArgs = papszArgs; + g_crtArgs = cArgs; + + *ppapszArgs = papszArgs; + } + else + { + /* + * The arguments are already UTF-8, no conversion needed. + */ + g_papszrtOrgArgs = papszOrgArgs; + g_papszrtArgs = papszOrgArgs; + g_crtArgs = cArgs; + } } return VINF_SUCCESS; @@ -316,6 +371,19 @@ static void rtR3SigChildHandler(int iSignal) static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath) { /* + * Early native initialization. + */ + int rc = rtR3InitNativeFirst(fFlags); + AssertMsgRCReturn(rc, ("rtR3InitNativeFirst failed with %Rrc\n", rc), rc); + + /* + * Disable error popups. + */ +#if defined(RT_OS_OS2) /** @todo move to private code. */ + DosError(FERR_DISABLEHARDERR); +#endif + + /* * Init C runtime locale before we do anything that may end up converting * paths or we'll end up using the "C" locale for path conversion. */ @@ -331,14 +399,9 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha #endif /* - * Disable error popups. + * Save the init flags. */ -#ifdef RT_OS_WINDOWS - UINT fOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX | fOldErrMode); -#elif defined(RT_OS_OS2) - DosError(FERR_DISABLEHARDERR); -#endif + g_fInitFlags |= fFlags; #if !defined(IN_GUEST) && !defined(RT_NO_GIP) # ifdef VBOX @@ -363,7 +426,7 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha * This must be done before everything else or else we'll call into threading * without having initialized TLS entries and suchlike. */ - int rc = rtThreadInit(); + rc = rtThreadInit(); AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) @@ -465,6 +528,12 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha IPRT_ALIGNMENT_CHECKS_ENABLE(); #endif + /* + * Final native initialization. + */ + rc = rtR3InitNativeFinal(fFlags); + AssertMsgRCReturn(rc, ("rtR3InitNativeFinal failed with %Rrc\n", rc), rc); + return VINF_SUCCESS; } @@ -483,7 +552,10 @@ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const cha static int rtR3Init(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath) { /* no entry log flow, because prefixes and thread may freak out. */ - Assert(!(fFlags & ~(RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_SUPLIB))); + Assert(!(fFlags & ~( RTR3INIT_FLAGS_DLL + | RTR3INIT_FLAGS_SUPLIB + | RTR3INIT_FLAGS_UNOBTRUSIVE + | RTR3INIT_FLAGS_UTF8_ARGV))); Assert(!(fFlags & RTR3INIT_FLAGS_DLL) || cArgs == 0); /* @@ -499,12 +571,23 @@ static int rtR3Init(uint32_t fFlags, int cArgs, char ***papszArgs, const char *p Assert(!g_fInitializing); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) if (fFlags & RTR3INIT_FLAGS_SUPLIB) + { SUPR3Init(NULL); + g_fInitFlags |= RTR3INIT_FLAGS_SUPLIB; + } #endif - if (!pszProgramPath) - return VINF_SUCCESS; - int rc = rtR3InitProgramPath(pszProgramPath); + if ( !(fFlags & RTR3INIT_FLAGS_UNOBTRUSIVE) + && (g_fInitFlags & RTR3INIT_FLAGS_UNOBTRUSIVE)) + { + g_fInitFlags &= ~RTR3INIT_FLAGS_UNOBTRUSIVE; + rtR3InitNativeObtrusive(); + rtThreadReInitObtrusive(); + } + + int rc = VINF_SUCCESS; + if (pszProgramPath) + rc = rtR3InitProgramPath(pszProgramPath); if (RT_SUCCESS(rc)) rc = rtR3InitArgv(fFlags, cArgs, papszArgs); return rc; @@ -557,6 +640,10 @@ RTR3DECL(int) RTR3InitEx(uint32_t iVersion, uint32_t fFlags, int cArgs, char *** return rtR3Init(fFlags, cArgs, papszArgs, pszProgramPath); } +RTR3DECL(bool) RTR3InitIsUnobtrusive(void) +{ + return RT_BOOL(g_fInitFlags & RTR3INIT_FLAGS_UNOBTRUSIVE); +} #if 0 /** @todo implement RTR3Term. */ RTR3DECL(void) RTR3Term(void) diff --git a/src/VBox/Runtime/r3/init.h b/src/VBox/Runtime/r3/init.h new file mode 100644 index 00000000..fae5c41f --- /dev/null +++ b/src/VBox/Runtime/r3/init.h @@ -0,0 +1,38 @@ +/* $Id: init.h $ */ +/** @file + * IPRT - Ring-3 initialization. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#ifndef ___r3_init_h +#define ___r3_init_h + +#include <iprt/types.h> + +DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags); +DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags); +DECLHIDDEN(void) rtR3InitNativeObtrusive(void); + +#endif + diff --git a/src/VBox/Runtime/r3/isofs.cpp b/src/VBox/Runtime/r3/isofs.cpp index 05f5da9d..16d0334f 100644 --- a/src/VBox/Runtime/r3/isofs.cpp +++ b/src/VBox/Runtime/r3/isofs.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp b/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp index 5582cef9..64edf958 100644 --- a/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp +++ b/src/VBox/Runtime/r3/linux/RTProcIsRunningByName-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp b/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp index a1da642c..e58365ac 100644 --- a/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp +++ b/src/VBox/Runtime/r3/linux/RTSystemShutdown-linux.cpp @@ -47,20 +47,24 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char * Assemble the argument vector. */ int iArg = 0; - const char *apszArgs[5]; + const char *apszArgs[6]; + + RT_BZERO(apszArgs, sizeof(apszArgs)); apszArgs[iArg++] = "/sbin/shutdown"; switch (fFlags & RTSYSTEM_SHUTDOWN_ACTION_MASK) { case RTSYSTEM_SHUTDOWN_HALT: - apszArgs[iArg++] = "--halt"; + apszArgs[iArg++] = "-h"; + apszArgs[iArg++] = "-H"; break; case RTSYSTEM_SHUTDOWN_REBOOT: - apszArgs[iArg++] = "--reboot"; + apszArgs[iArg++] = "-r"; break; case RTSYSTEM_SHUTDOWN_POWER_OFF: case RTSYSTEM_SHUTDOWN_POWER_OFF_HALT: - apszArgs[iArg++] = "--poweroff"; + apszArgs[iArg++] = "-h"; + apszArgs[iArg++] = "-P"; break; } @@ -95,4 +99,3 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char } RT_EXPORT_SYMBOL(RTSystemShutdown); - diff --git a/src/VBox/Runtime/r3/linux/fileaio-linux.cpp b/src/VBox/Runtime/r3/linux/fileaio-linux.cpp index 51215de6..2cc8feb1 100644 --- a/src/VBox/Runtime/r3/linux/fileaio-linux.cpp +++ b/src/VBox/Runtime/r3/linux/fileaio-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -183,6 +183,8 @@ typedef struct RTFILEAIOCTXINTERNAL volatile bool fWokenUp; /** Flag whether the thread is currently waiting in the syscall. */ volatile bool fWaiting; + /** Flags given during creation. */ + uint32_t fFlags; /** Magic value (RTFILEAIOCTX_MAGIC). */ uint32_t u32Magic; } RTFILEAIOCTXINTERNAL; @@ -472,10 +474,12 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered) } -RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags) { PRTFILEAIOCTXINTERNAL pCtxInt; AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); /* The kernel interface needs a maximum. */ if (cAioReqsMax == RTFILEAIO_UNLIMITED_REQS) @@ -493,6 +497,7 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) pCtxInt->fWaiting = false; pCtxInt->hThreadWait = NIL_RTTHREAD; pCtxInt->cRequestsMax = cAioReqsMax; + pCtxInt->fFlags = fFlags; pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; *phAioCtx = (RTFILEAIOCTX)pCtxInt; } @@ -658,7 +663,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL /* * Can't wait if there are not requests around. */ - if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0)) + if ( RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0) + && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS)) return VERR_FILE_AIO_NO_REQUEST; /* diff --git a/src/VBox/Runtime/r3/linux/mp-linux.cpp b/src/VBox/Runtime/r3/linux/mp-linux.cpp index 54304aba..210f75a7 100644 --- a/src/VBox/Runtime/r3/linux/mp-linux.cpp +++ b/src/VBox/Runtime/r3/linux/mp-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,6 +33,9 @@ #include <errno.h> #include <iprt/mp.h> +#include "internal/iprt.h" + +#include <iprt/alloca.h> #include <iprt/cpuset.h> #include <iprt/assert.h> #include <iprt/string.h> @@ -82,7 +85,7 @@ static uint32_t rtMpLinuxGetFrequency(RTCPUID idCpu) while (fgets(sz, sizeof(sz), pFile)) { char *psz; - if ( !strncmp(sz, "processor", 9) + if ( !strncmp(sz, RT_STR_TUPLE("processor")) && (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':') && (psz = strchr(sz, ':'))) { @@ -93,7 +96,7 @@ static uint32_t rtMpLinuxGetFrequency(RTCPUID idCpu) idCpuFound = iCpu; } else if ( idCpu == idCpuFound - && !strncmp(sz, "cpu MHz", 7) + && !strncmp(sz, RT_STR_TUPLE("cpu MHz")) && (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':') && (psz = strchr(sz, ':'))) { @@ -177,6 +180,36 @@ RTDECL(RTCPUID) RTMpGetCount(void) } +RTDECL(RTCPUID) RTMpGetCoreCount(void) +{ + RTCPUID cMax = rtMpLinuxMaxCpus(); + uint32_t *paidCores = (uint32_t *)alloca(sizeof(paidCores[0]) * (cMax + 1)); + uint32_t *paidPckgs = (uint32_t *)alloca(sizeof(paidPckgs[0]) * (cMax + 1)); + uint32_t cCores = 0; + for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) + { + if (RTMpIsCpuPossible(idCpu)) + { + uint32_t idCore = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/core_id", (int)idCpu); + uint32_t idPckg = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/physical_package_id", (int)idCpu); + uint32_t i; + for (i = 0; i < cCores; i++) + if ( paidCores[i] == idCore + && paidPckgs[i] == idPckg) + break; + if (i >= cCores) + { + paidCores[cCores] = idCore; + paidPckgs[cCores] = idPckg; + cCores++; + } + } + } + Assert(cCores > 0); + return cCores; +} + + RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { RTCpuSetEmpty(pSet); @@ -196,6 +229,37 @@ RTDECL(RTCPUID) RTMpGetOnlineCount(void) } +RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void) +{ + RTCPUID cMax = rtMpLinuxMaxCpus(); + uint32_t *paidCores = (uint32_t *)alloca(sizeof(paidCores[0]) * (cMax + 1)); + uint32_t *paidPckgs = (uint32_t *)alloca(sizeof(paidPckgs[0]) * (cMax + 1)); + uint32_t cCores = 0; + for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) + { + if (RTMpIsCpuOnline(idCpu)) + { + uint32_t idCore = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/core_id", (int)idCpu); + uint32_t idPckg = (uint32_t)RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/topology/physical_package_id", (int)idCpu); + uint32_t i; + for (i = 0; i < cCores; i++) + if ( paidCores[i] == idCore + && paidPckgs[i] == idPckg) + break; + if (i >= cCores) + { + paidCores[cCores] = idCore; + paidPckgs[cCores] = idPckg; + cCores++; + } + } + } + Assert(cCores > 0); + return cCores; +} + + + RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu) { int64_t kHz = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu); diff --git a/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp b/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp index 3ab0860b..cb43d9d0 100644 --- a/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp +++ b/src/VBox/Runtime/r3/linux/rtProcInitExePath-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/linux/sched-linux.cpp b/src/VBox/Runtime/r3/linux/sched-linux.cpp index 3972a6af..1e85af5b 100644 --- a/src/VBox/Runtime/r3/linux/sched-linux.cpp +++ b/src/VBox/Runtime/r3/linux/sched-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp b/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp index 01094187..b623c846 100644 --- a/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp +++ b/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/linux/semmutex-linux.cpp b/src/VBox/Runtime/r3/linux/semmutex-linux.cpp index 1be76f4e..60abc1ed 100644 --- a/src/VBox/Runtime/r3/linux/semmutex-linux.cpp +++ b/src/VBox/Runtime/r3/linux/semmutex-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/linux/sysfs.cpp b/src/VBox/Runtime/r3/linux/sysfs.cpp index aa1060ac..15309330 100644 --- a/src/VBox/Runtime/r3/linux/sysfs.cpp +++ b/src/VBox/Runtime/r3/linux/sysfs.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -53,8 +53,7 @@ * Constructs the path of a sysfs file from the format parameters passed, * prepending a prefix if the path is relative. * - * @returns The number of characters returned, or -1 and errno set to ERANGE on - * failure. + * @returns The number of characters returned, or an iprt error code on failure. * * @param pszPrefix The prefix to prepend if the path is relative. Must end * in '/'. @@ -70,8 +69,8 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) { size_t cchPrefix = strlen(pszPrefix); - AssertReturnStmt(pszPrefix[cchPrefix - 1] == '/', errno = ERANGE, -1); - AssertReturnStmt(cchBuf > cchPrefix + 1, errno = ERANGE, -1); + AssertReturn(pszPrefix[cchPrefix - 1] == '/', VERR_INVALID_PARAMETER); + AssertReturn(cchBuf > cchPrefix + 1, VERR_INVALID_PARAMETER); /** @todo While RTStrPrintfV prevents overflows, it doesn't make it easy to * check for truncations. RTPath should provide some formatters and @@ -80,7 +79,7 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va); if (*pszBuf != '/') { - AssertReturnStmt(cchBuf >= cch + cchPrefix + 1, errno = ERANGE, -1); + AssertReturn(cchBuf >= cch + cchPrefix + 1, VERR_BUFFER_OVERFLOW); memmove(pszBuf + cchPrefix, pszBuf, cch + 1); memcpy(pszBuf, pszPrefix, cchPrefix); cch += cchPrefix; @@ -93,8 +92,8 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, * Constructs the path of a sysfs file from the format parameters passed, * prepending a prefix if the path is relative. * - * @returns The number of characters returned, or -1 and errno set to ERANGE on - * failure. + * @returns The number of characters returned, or an iprt error code on failure. + * @note Unused. * * @param pszPrefix The prefix to prepend if the path is relative. Must end * in '/'. @@ -131,7 +130,11 @@ static ssize_t rtLinuxConstructPath(char *pszBuf, size_t cchBuf, */ static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) { - return rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va); + ssize_t rc = rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va); + if (rc >= 0) + return rc; + errno = ERANGE; + return -1; } @@ -409,125 +412,118 @@ RTDECL(ssize_t) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char } -static ssize_t rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, const char *pszBasePath, - char *pszBuf, size_t cchBuf) +/** Search for a device node with the number @a DevNum and the type (character + * or block) @a fMode below the path @a pszPath. @a pszPath MUST point to a + * buffer of size at least RTPATH_MAX which will be modified during the function + * execution. On successful return it will contain the path to the device node + * found. */ +/** @note This function previously used a local stack buffer of size RTPATH_MAX + * to construct the path passed to the next recursive call, which used up 4K + * of stack space per iteration and caused a stack overflow on a path with + * too many components. */ +static int rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, + char *pszPath) { + int rc; + PRTDIR pDir; + size_t const cchPath = strlen(pszPath); + /* * Check assumptions made by the code below. */ - size_t const cchBasePath = strlen(pszBasePath); - AssertReturnStmt(cchBasePath < RTPATH_MAX - 10U, errno = ENAMETOOLONG, -1); - - ssize_t rcRet; - PRTDIR pDir; - int rc = RTDirOpen(&pDir, pszBasePath); + AssertReturn(cchPath < RTPATH_MAX - 10U, VERR_BUFFER_OVERFLOW); + rc = RTDirOpen(&pDir, pszPath); if (RT_SUCCESS(rc)) { - char szPath[RTPATH_MAX]; /** @todo 4K per recursion - can easily be optimized away by passing it along pszBasePath - and only remember the length. */ - memcpy(szPath, pszBasePath, cchBasePath + 1); - for (;;) { RTDIRENTRYEX Entry; - rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); + rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, + RTPATH_F_ON_LINK); if (RT_FAILURE(rc)) - { - errno = rc == VERR_NO_MORE_FILES - ? ENOENT - : rc == VERR_BUFFER_OVERFLOW - ? EOVERFLOW - : EIO; - rcRet = -1; break; - } if (RTFS_IS_SYMLINK(Entry.Info.Attr.fMode)) continue; - + pszPath[cchPath] = '\0'; + rc = RTPathAppend(pszPath, RTPATH_MAX, Entry.szName); + if (RT_FAILURE(rc)) + break; /* Do the matching. */ if ( Entry.Info.Attr.u.Unix.Device == DevNum && (Entry.Info.Attr.fMode & RTFS_TYPE_MASK) == fMode) - { - rcRet = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", Entry.szName); break; - } - /* Recurse into subdirectories. */ if (!RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)) continue; if (Entry.szName[0] == '.') continue; - - szPath[cchBasePath] = '\0'; - rc = RTPathAppend(szPath, sizeof(szPath) - 1, Entry.szName); /* -1: for slash */ - if (RT_FAILURE(rc)) - { - errno = ENAMETOOLONG; - rcRet = -1; - break; - } - strcat(&szPath[cchBasePath], "/"); - rcRet = rtLinuxFindDevicePathRecursive(DevNum, fMode, szPath, pszBuf, cchBuf); - if (rcRet >= 0 || errno != ENOENT) + rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, pszPath); + if (RT_SUCCESS(rc) || rc != VERR_NO_MORE_FILES) break; } RTDirClose(pDir); } - else - { - rcRet = -1; - errno = RTErrConvertToErrno(rc); - } - return rcRet; + return rc; } -RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, - const char *pszSuggestion, va_list va) +RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, + size_t cchBuf, const char *pszSuggestion, + va_list va) { - AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1); - AssertReturnStmt( fMode == RTFS_TYPE_DEV_CHAR - || fMode == RTFS_TYPE_DEV_BLOCK, - errno = EINVAL, -1); + char szFilename[RTPATH_MAX]; + int rc = VINF_TRY_AGAIN; + AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER); + AssertReturn( fMode == RTFS_TYPE_DEV_CHAR + || fMode == RTFS_TYPE_DEV_BLOCK, + VERR_INVALID_PARAMETER); if (pszSuggestion) { /* * Construct the filename and read the link. */ - char szFilename[RTPATH_MAX]; - int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", pszSuggestion, va); - if (rc == -1) - return -1; - - /* - * Check whether the caller's suggestion was right. - */ - RTFSOBJINFO Info; - rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX); - if ( RT_SUCCESS(rc) - && Info.Attr.u.Unix.Device == DevNum - && (Info.Attr.fMode & RTFS_TYPE_MASK) == fMode) + rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", + pszSuggestion, va); + if (rc > 0) { - size_t cchPath = strlen(szFilename); - if (cchPath >= cchBuf) - { - errno = EOVERFLOW; - return -1; - } - memcpy(pszBuf, szFilename, cchPath + 1); - return cchPath; + /* + * Check whether the caller's suggestion was right. + */ + RTFSOBJINFO Info; + rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX); + if ( rc == VERR_PATH_NOT_FOUND + || rc == VERR_FILE_NOT_FOUND + || ( RT_SUCCESS(rc) + && ( Info.Attr.u.Unix.Device != DevNum + || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode))) + /* The suggestion was wrong, fall back on the brute force attack. */ + rc = VINF_TRY_AGAIN; } - - /* The suggestion was wrong, fall back on the brute force attack. */ } - return rtLinuxFindDevicePathRecursive(DevNum, fMode, "/dev/", pszBuf, cchBuf); + if (rc == VINF_TRY_AGAIN) + { + RTStrCopy(szFilename, sizeof(szFilename), "/dev/"); + rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, szFilename); + } + if (RT_SUCCESS(rc)) + { + size_t cchPath = strlen(szFilename); + if (cchPath >= cchBuf) + return VERR_BUFFER_OVERFLOW; + memcpy(pszBuf, szFilename, cchPath + 1); + return cchPath; + } + return rc; } -RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, - const char *pszSuggestion, ...) +/** @todo Do we really need to return the string length? If the caller is + * interested (the current ones aren't) they can check themselves. */ +RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, + size_t cchBuf, const char *pszSuggestion, + ...) { va_list va; va_start(va, pszSuggestion); diff --git a/src/VBox/Runtime/r3/linux/systemmem-linux.cpp b/src/VBox/Runtime/r3/linux/systemmem-linux.cpp index f3234403..23fe70b8 100644 --- a/src/VBox/Runtime/r3/linux/systemmem-linux.cpp +++ b/src/VBox/Runtime/r3/linux/systemmem-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,7 +33,9 @@ #include <iprt/err.h> #include <iprt/assert.h> +#include <iprt/string.h> +#include <stdio.h> #include <errno.h> /* Satisfy compiller warning */ @@ -50,7 +52,7 @@ RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb) int rc = sysinfo(&info); if (rc == 0) { - *pcb = (uint64_t)(info.totalram * (unsigned long)info.mem_unit); + *pcb = (uint64_t)info.totalram * info.mem_unit; return VINF_SUCCESS; } return RTErrConvertFromErrno(errno); @@ -61,11 +63,45 @@ RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb) { AssertPtrReturn(pcb, VERR_INVALID_POINTER); + FILE *pFile = fopen("/proc/meminfo", "r"); + if (pFile) + { + int rc = VERR_NOT_FOUND; + uint64_t cbTotal = 0; + uint64_t cbFree = 0; + uint64_t cbBuffers = 0; + uint64_t cbCached = 0; + char sz[256]; + while (fgets(sz, sizeof(sz), pFile)) + { + if (!strncmp(sz, RT_STR_TUPLE("MemTotal:"))) + rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("MemTotal:")]), NULL, 0, &cbTotal); + else if (!strncmp(sz, RT_STR_TUPLE("MemFree:"))) + rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("MemFree:")]), NULL, 0, &cbFree); + else if (!strncmp(sz, RT_STR_TUPLE("Buffers:"))) + rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("Buffers:")]), NULL, 0, &cbBuffers); + else if (!strncmp(sz, RT_STR_TUPLE("Cached:"))) + rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("Cached:")]), NULL, 0, &cbCached); + if (RT_FAILURE(rc)) + break; + } + fclose(pFile); + if (RT_SUCCESS(rc)) + { + *pcb = (cbFree + cbBuffers + cbCached) * _1K; + return VINF_SUCCESS; + } + } + /* + * Fallback (e.g. /proc not mapped) to sysinfo. Less accurat because there + * is no information about the cached memory. 'Cached:' from above is only + * accessible through proc :-( + */ struct sysinfo info; int rc = sysinfo(&info); if (rc == 0) { - *pcb = (uint64_t)(info.freeram * (unsigned long)info.mem_unit); + *pcb = ((uint64_t)info.freeram + info.bufferram) * info.mem_unit; return VINF_SUCCESS; } return RTErrConvertFromErrno(errno); diff --git a/src/VBox/Runtime/r3/linux/time-linux.cpp b/src/VBox/Runtime/r3/linux/time-linux.cpp index a9de927e..ab9c0e5a 100644 --- a/src/VBox/Runtime/r3/linux/time-linux.cpp +++ b/src/VBox/Runtime/r3/linux/time-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/nt/Makefile.kup b/src/VBox/Runtime/r3/nt/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/VBox/Runtime/r3/nt/Makefile.kup diff --git a/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp new file mode 100644 index 00000000..f93f6e4e --- /dev/null +++ b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp @@ -0,0 +1,697 @@ +/* $Id: direnum-r3-nt.cpp $ */ +/** @file + * IPRT - Directory Enumeration, Native NT. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_DIR +#include "internal-r3-nt.h" + +#include <iprt/dir.h> +#include <iprt/path.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/file.h> +#include <iprt/log.h> +#include "internal/fs.h" +#include "internal/dir.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** Whether to return a single record (TRUE) or multiple (FALSE)o. */ +#define RTDIR_NT_SINGLE_RECORD FALSE + +/** Go hard on record chaining (has slight performance impact). */ +#ifdef RT_STRICT +# define RTDIR_NT_STRICT +#endif + + +/* ASSUMES FileID comes after ShortName and the structus are identical up to that point. */ +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, NextEntryOffset, FILE_ID_BOTH_DIR_INFORMATION, NextEntryOffset); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileIndex , FILE_ID_BOTH_DIR_INFORMATION, FileIndex ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, CreationTime , FILE_ID_BOTH_DIR_INFORMATION, CreationTime ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastAccessTime , FILE_ID_BOTH_DIR_INFORMATION, LastAccessTime ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastWriteTime , FILE_ID_BOTH_DIR_INFORMATION, LastWriteTime ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ChangeTime , FILE_ID_BOTH_DIR_INFORMATION, ChangeTime ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EndOfFile , FILE_ID_BOTH_DIR_INFORMATION, EndOfFile ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, AllocationSize , FILE_ID_BOTH_DIR_INFORMATION, AllocationSize ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileAttributes , FILE_ID_BOTH_DIR_INFORMATION, FileAttributes ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileNameLength , FILE_ID_BOTH_DIR_INFORMATION, FileNameLength ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EaSize , FILE_ID_BOTH_DIR_INFORMATION, EaSize ); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortNameLength, FILE_ID_BOTH_DIR_INFORMATION, ShortNameLength); +AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortName , FILE_ID_BOTH_DIR_INFORMATION, ShortName ); + + + +size_t rtDirNativeGetStructSize(const char *pszPath) +{ + NOREF(pszPath); + return sizeof(RTDIR); +} + + +int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) +{ + /* + * Convert the filter to UTF-16. + */ + int rc; + pDir->pNtFilterStr = NULL; + if ( pDir->cchFilter > 0 + && pDir->enmFilter == RTDIRFILTER_WINNT) + { + PRTUTF16 pwszTmp; + rc = RTStrToUtf16(pDir->pszFilter, &pwszTmp); + if (RT_FAILURE(rc)) + return rc; + pDir->NtFilterStr.Buffer = pwszTmp; + pDir->NtFilterStr.Length = pDir->NtFilterStr.MaximumLength = (uint16_t)(RTUtf16Len(pwszTmp) * sizeof(RTUTF16)); + pDir->pNtFilterStr = &pDir->NtFilterStr; + } + + /* + * Try open the directory + */ +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + bool fObjDir; +#endif + rc = rtNtPathOpenDir(pszPathBuf, + FILE_READ_DATA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE, + &pDir->hDir, +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + &fObjDir +#else + NULL +#endif + ); + if (RT_SUCCESS(rc)) + { + /* + * Init data. + */ + pDir->fDataUnread = false; /* spelling it out */ +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + if (fObjDir) + pDir->enmInfoClass = FileMaximumInformation; /* object directory. */ +#endif + } + return rc; +} + + +RTDECL(int) RTDirClose(PRTDIR pDir) +{ + /* + * Validate input. + */ + if (!pDir) + return VERR_INVALID_PARAMETER; + if (pDir->u32Magic != RTDIR_MAGIC) + { + AssertMsgFailed(("Invalid pDir=%p\n", pDir)); + return VERR_INVALID_PARAMETER; + } + + /* + * Close the handle. + */ + pDir->u32Magic = ~RTDIR_MAGIC; + if (pDir->hDir != MY_INVALID_HANDLE_VALUE) + { + int rc = rtNtPathClose(pDir->hDir); + AssertRC(rc); + pDir->hDir = MY_INVALID_HANDLE_VALUE; + } + RTStrFree(pDir->pszName); + pDir->pszName = NULL; + RTUtf16Free(pDir->NtFilterStr.Buffer); + pDir->NtFilterStr.Buffer = NULL; + RTMemFree(pDir->pabBuffer); + pDir->pabBuffer = NULL; + RTMemFree(pDir); + + return VINF_SUCCESS; +} + + +/** + * Checks the validity of the current record. + * + * @returns IPRT status code + * @param pThis The directory instance data. + */ +static int rtDirNtCheckRecord(PRTDIR pThis) +{ +#ifdef RTDIR_NT_STRICT +# ifdef IPRT_WITH_NT_PATH_PASSTHRU + if (pThis->enmInfoClass != FileMaximumInformation) +# endif + { + uintptr_t uEndAddr; + if (pThis->enmInfoClass == FileIdBothDirectoryInformation) + uEndAddr = (uintptr_t)&pThis->uCurData.pBothId->FileName[0]; + else + uEndAddr = (uintptr_t)&pThis->uCurData.pBoth->FileName[0]; + AssertReturn(uEndAddr < (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE); + + AssertReturn(pThis->uCurData.pBoth->FileNameLength < _64K, VERR_FILENAME_TOO_LONG); + AssertReturn((pThis->uCurData.pBoth->FileNameLength & 1) == 0, VERR_IO_GEN_FAILURE); + + uEndAddr += pThis->uCurData.pBoth->FileNameLength; + AssertReturn(uEndAddr <= (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE); + + AssertReturn((unsigned)pThis->uCurData.pBoth->ShortNameLength <= sizeof(pThis->uCurData.pBoth->ShortName), + VERR_IO_GEN_FAILURE); + } +#endif + + return VINF_SUCCESS; +} + + +/** + * Advances the buffer pointer. + * + * @param pThis The directory instance data. + */ +static int rtDirNtAdvanceBuffer(PRTDIR pThis) +{ + int rc; + +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + if (pThis->enmInfoClass == FileMaximumInformation) + { + pThis->uCurData.pObjDir++; + pThis->fDataUnread = pThis->uCurData.pObjDir->Name.Length != 0; + return VINF_SUCCESS; + } +#endif + + pThis->fDataUnread = false; + + uint32_t const offNext = pThis->uCurData.pBoth->NextEntryOffset; + if (offNext == 0) + return VINF_SUCCESS; + +#ifdef RTDIR_NT_STRICT + /* Make sure the next-record offset is beyond the current record. */ + size_t cbRec; + if (pThis->enmInfoClass == FileIdBothDirectoryInformation) + cbRec = RT_UOFFSETOF(FILE_ID_BOTH_DIR_INFORMATION, FileName); + else + cbRec = RT_UOFFSETOF(FILE_BOTH_DIR_INFORMATION, FileName); + cbRec += pThis->uCurData.pBoth->FileNameLength; + AssertReturn(offNext >= cbRec, VERR_IO_GEN_FAILURE); +#endif + pThis->uCurData.u += offNext; + + rc = rtDirNtCheckRecord(pThis); + pThis->fDataUnread = RT_SUCCESS(rc); + 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; +} + + +/** + * Converts the name from UTF-16 to UTF-8. + * + * Fortunately, the names are relative to the directory, so we won't have to do + * any sweaty path style coversion. :-) + * + * @returns IPRT status code + * @param pThis The directory instance data. + * @param cbName The file name length in bytes. + * @param pwsName The file name, not terminated. + */ +static int rtDirNtConvertName(PRTDIR pThis, uint32_t cbName, PCRTUTF16 pwsName) +{ + int rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName); + if (RT_SUCCESS(rc)) + { + if (!pThis->cbNameAlloc) + pThis->cbNameAlloc = pThis->cchName + 1; + } + else if (rc == VERR_BUFFER_OVERFLOW) + { + RTStrFree(pThis->pszName); + pThis->pszName = NULL; + pThis->cbNameAlloc = 0; + + rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName); + if (RT_SUCCESS(rc)) + pThis->cbNameAlloc = pThis->cchName + 1; + } + Assert(RT_SUCCESS(rc) ? pThis->pszName != NULL : pThis->pszName == NULL); + return rc; +} + + +/** + * Converts the name of the current record. + * + * @returns IPRT status code. + * @param pThis The directory instance data. + */ +static int rtDirNtConvertCurName(PRTDIR pThis) +{ + switch (pThis->enmInfoClass) + { + case FileIdBothDirectoryInformation: + return rtDirNtConvertName(pThis, pThis->uCurData.pBothId->FileNameLength, pThis->uCurData.pBothId->FileName); + case FileBothDirectoryInformation: + return rtDirNtConvertName(pThis, pThis->uCurData.pBoth->FileNameLength, pThis->uCurData.pBoth->FileName); +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + case FileMaximumInformation: + return rtDirNtConvertName(pThis, pThis->uCurData.pObjDir->Name.Length, pThis->uCurData.pObjDir->Name.Buffer); +#endif + + default: + AssertFailedReturn(VERR_INTERNAL_ERROR_3); + } +} + + +RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry) +{ + int rc; + + /* + * Validate input. + */ + AssertPtrReturn(pDir, VERR_INVALID_POINTER); + AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE); + AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER); + size_t cbDirEntry = sizeof(*pDirEntry); + if (pcbDirEntry) + { + cbDirEntry = *pcbDirEntry; + AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]), + ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])), + VERR_INVALID_PARAMETER); + } + + /* + * Fetch data? + */ + if (!pDir->fDataUnread) + { + rc = rtDirNtFetchMore(pDir); + if (RT_FAILURE(rc)) + return rc; + } + + /* + * Convert the filename to UTF-8. + */ + rc = rtDirNtConvertCurName(pDir); + if (RT_FAILURE(rc)) + return rc; + + /* + * Check if we've got enough space to return the data. + */ + const char *pszName = pDir->pszName; + const size_t cchName = pDir->cchName; + const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName; + if (pcbDirEntry) + *pcbDirEntry = cbRequired; + if (cbRequired > cbDirEntry) + return VERR_BUFFER_OVERFLOW; + + /* + * Setup the returned data. + */ + pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName); + memcpy(pDirEntry->szName, pszName, cchName + 1); + + pDirEntry->INodeId = pDir->enmInfoClass == FileIdBothDirectoryInformation + ? pDir->uCurData.pBothId->FileId.QuadPart : 0; + +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + if (pDir->enmInfoClass != FileMaximumInformation) +#endif + { + switch ( pDir->uCurData.pBoth->FileAttributes + & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY)) + { + default: + AssertFailed(); + case 0: + pDirEntry->enmType = RTDIRENTRYTYPE_FILE; + break; + + case FILE_ATTRIBUTE_DIRECTORY: + pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY; + break; + + case FILE_ATTRIBUTE_REPARSE_POINT: + case FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY: + pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK; + break; + } + } +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + else + { + pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN; + if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, + RT_STR_TUPLE("Directory"))) + pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY; + else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, + RT_STR_TUPLE("SymbolicLink"))) + pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK; + } +#endif + + return rtDirNtAdvanceBuffer(pDir); +} + + +RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, + RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) +{ + int rc; + + /* + * Validate input. + */ + AssertPtrReturn(pDir, VERR_INVALID_POINTER); + AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE); + AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER); + + AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, + VERR_INVALID_PARAMETER); + AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); + + size_t cbDirEntry = sizeof(*pDirEntry); + if (pcbDirEntry) + { + cbDirEntry = *pcbDirEntry; + AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]), + ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])), + VERR_INVALID_PARAMETER); + } + + /* + * Fetch data? + */ + if (!pDir->fDataUnread) + { + rc = rtDirNtFetchMore(pDir); + if (RT_FAILURE(rc)) + return rc; + } + + /* + * Convert the filename to UTF-8. + */ + rc = rtDirNtConvertCurName(pDir); + if (RT_FAILURE(rc)) + return rc; + + /* + * Check if we've got enough space to return the data. + */ + const char *pszName = pDir->pszName; + const size_t cchName = pDir->cchName; + const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName; + if (pcbDirEntry) + *pcbDirEntry = cbRequired; + if (cbRequired > cbDirEntry) + return VERR_BUFFER_OVERFLOW; + + /* + * Setup the returned data. + */ + PFILE_BOTH_DIR_INFORMATION pBoth = pDir->uCurData.pBoth; + + pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName); + memcpy(pDirEntry->szName, pszName, cchName + 1); + memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName)); +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + if (pDir->enmInfoClass != FileMaximumInformation) +#endif + { + uint8_t cbShort = pBoth->ShortNameLength; + if (cbShort > 0) + { + AssertStmt(cbShort < sizeof(pDirEntry->wszShortName), cbShort = sizeof(pDirEntry->wszShortName) - 2); + memcpy(pDirEntry->wszShortName, pBoth->ShortName, cbShort); + pDirEntry->cwcShortName = cbShort / 2; + } + else + pDirEntry->cwcShortName = 0; + + pDirEntry->Info.cbObject = pBoth->EndOfFile.QuadPart; + pDirEntry->Info.cbAllocated = pBoth->AllocationSize.QuadPart; + + Assert(sizeof(uint64_t) == sizeof(pBoth->CreationTime)); + RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, pBoth->CreationTime.QuadPart); + RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, pBoth->LastAccessTime.QuadPart); + RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, pBoth->LastWriteTime.QuadPart); + RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, pBoth->ChangeTime.QuadPart); + + pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pBoth->FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, + pszName, cchName); + } +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + else + { + pDirEntry->cwcShortName = 0; + pDirEntry->Info.cbObject = 0; + pDirEntry->Info.cbAllocated = 0; + RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, 0); + RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, 0); + RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, 0); + RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, 0); + + if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, + RT_STR_TUPLE("Directory"))) + pDirEntry->Info.Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; + else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, + RT_STR_TUPLE("SymbolicLink"))) + pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777; + else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, + RT_STR_TUPLE("Device"))) + pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666; + else + pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666; + } +#endif + + /* + * Requested attributes (we cannot provide anything actually). + */ + switch (enmAdditionalAttribs) + { + case RTFSOBJATTRADD_EASIZE: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + if (pDir->enmInfoClass == FileMaximumInformation) + pDirEntry->Info.Attr.u.EASize.cb = 0; + else +#endif + pDirEntry->Info.Attr.u.EASize.cb = pBoth->EaSize; + break; + + case RTFSOBJATTRADD_UNIX: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; + pDirEntry->Info.Attr.u.Unix.uid = ~0U; + pDirEntry->Info.Attr.u.Unix.gid = ~0U; + pDirEntry->Info.Attr.u.Unix.cHardlinks = 1; + pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */ + pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */ + pDirEntry->Info.Attr.u.Unix.fFlags = 0; + pDirEntry->Info.Attr.u.Unix.GenerationId = 0; + pDirEntry->Info.Attr.u.Unix.Device = 0; + break; + + case RTFSOBJATTRADD_NOTHING: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; + break; + + case RTFSOBJATTRADD_UNIX_OWNER: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; + pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U; + pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ + break; + + case RTFSOBJATTRADD_UNIX_GROUP: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; + pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U; + pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0'; + break; + + default: + AssertMsgFailed(("Impossible!\n")); + return VERR_INTERNAL_ERROR; + } + + /* + * Follow links if requested. + */ + if ( (fFlags & RTPATH_F_FOLLOW_LINK) + && RTFS_IS_SYMLINK(fFlags)) + { + /** @todo Symlinks: Find[First|Next]FileW will return info about + the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */ + } + + /* + * Finally advance the buffer. + */ + return rtDirNtAdvanceBuffer(pDir); +} + diff --git a/src/VBox/Runtime/r3/nt/fs-nt.cpp b/src/VBox/Runtime/r3/nt/fs-nt.cpp new file mode 100644 index 00000000..314059de --- /dev/null +++ b/src/VBox/Runtime/r3/nt/fs-nt.cpp @@ -0,0 +1,284 @@ +/* $Id: fs-nt.cpp $ */ +/** @file + * IPRT - File System, Native NT. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_FS +#include "internal-r3-nt.h" + +#include <iprt/fs.h> +#include <iprt/path.h> +#include <iprt/string.h> +#include <iprt/param.h> +#include <iprt/err.h> +#include <iprt/log.h> +#include <iprt/assert.h> +#include "internal/fs.h" + + + + +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; +} + + +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; +} + + +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) 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; +} + diff --git a/src/VBox/Runtime/r3/nt/internal-r3-nt.h b/src/VBox/Runtime/r3/nt/internal-r3-nt.h new file mode 100644 index 00000000..0a970965 --- /dev/null +++ b/src/VBox/Runtime/r3/nt/internal-r3-nt.h @@ -0,0 +1,140 @@ +/* $Id: internal-r3-nt.h $ */ +/** @file + * IPRT - Internal Header for the Native NT code. + */ + +/* + * Copyright (C) 2010-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#ifndef ___internal_r3_nt_h___ +#define ___internal_r3_nt_h___ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <ntstatus.h> +#ifdef IPRT_NT_USE_WINTERNL +# define WIN32_NO_STATUS +# include <windef.h> +# include <winnt.h> +# include <winternl.h> +# define IPRT_NT_NEED_API_GROUP_1 + +#elif defined(IPRT_NT_USE_WDM) +# include <wdm.h> +# define IPRT_NT_NEED_API_GROUP_1 + +#else +# include <ntifs.h> +#endif +#include "internal/iprt.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** Indicates that we're targetting native NT in the current source. */ +#define RT_USE_NATIVE_NT 1 +/** Initializes a IO_STATUS_BLOCK. */ +#define MY_IO_STATUS_BLOCK_INITIALIZER { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 } +/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */ +#define MY_INVALID_HANDLE_VALUE ( (HANDLE)~(uintptr_t)0 ) + +#ifdef DEBUG_bird +/** Enables the "\\!\" NT path pass thru as well as hacks for listing NT object + * directories. */ +# define IPRT_WITH_NT_PATH_PASSTHRU 1 +#endif + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, + ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + PHANDLE phHandle, PULONG_PTR puDisposition); +int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions, + ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir); +int rtNtPathClose(HANDLE hHandle); + + +/** + * Internal helper for comparing a WCHAR string with a char string. + * + * @returns @c true if equal, @c false if not. + * @param pwsz1 The first string. + * @param cb1 The length of the first string, in bytes. + * @param psz2 The second string. + * @param cch2 The length of the second string. + */ +DECLINLINE(bool) rtNtCompWideStrAndAscii(WCHAR const *pwsz1, size_t cch1, const char *psz2, size_t cch2) +{ + if (cch1 != cch2 * 2) + return false; + while (cch2-- > 0) + { + unsigned ch1 = *pwsz1++; + unsigned ch2 = (unsigned char)*psz2++; + if (ch1 != ch2) + return false; + } + return true; +} + + +/******************************************************************************* +* NT APIs * +*******************************************************************************/ + +RT_C_DECLS_BEGIN + +#ifdef IPRT_NT_NEED_API_GROUP_1 + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION; +typedef FILE_FS_ATTRIBUTE_INFORMATION *PFILE_FS_ATTRIBUTE_INFORMATION; +extern "C" NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS); + +#endif + +NTSTATUS NTAPI NtOpenDirectoryObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); + +typedef struct _OBJECT_DIRECTORY_INFORMATION +{ + UNICODE_STRING Name; + UNICODE_STRING TypeName; +} OBJECT_DIRECTORY_INFORMATION; +typedef OBJECT_DIRECTORY_INFORMATION *POBJECT_DIRECTORY_INFORMATION; + +NTSTATUS NTAPI NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG); + + +RT_C_DECLS_END + +#endif + diff --git a/src/VBox/Runtime/r3/nt/pathint-nt.cpp b/src/VBox/Runtime/r3/nt/pathint-nt.cpp new file mode 100644 index 00000000..a68f0597 --- /dev/null +++ b/src/VBox/Runtime/r3/nt/pathint-nt.cpp @@ -0,0 +1,356 @@ +/* $Id: pathint-nt.cpp $ */ +/** @file + * IPRT - Native NT, Internal Path stuff. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_FS +#include "internal-r3-nt.h" + +#include <iprt/path.h> +#include <iprt/string.h> +#include <iprt/err.h> +#include <iprt/assert.h> + + + +/** + * Handles the pass thru case. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. + * @param phRootDir Where to return the root handle, if applicable. + * @param pszPath The UTF-8 path. + */ +static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath) +{ + PRTUTF16 pwszPath = NULL; + size_t cwcLen; + int rc = RTStrToUtf16Ex(pszPath + 1, RTSTR_MAX, &pwszPath, 0, &cwcLen); + if (RT_SUCCESS(rc)) + { + if (cwcLen < _32K - 1) + { + pwszPath[0] = '\\'; + pwszPath[1] = '.'; + pwszPath[2] = '\\'; + + pNtName->Buffer = pwszPath; + pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2); + *phRootDir = NULL; + return VINF_SUCCESS; + } + + RTUtf16Free(pwszPath); + rc = VERR_FILENAME_TOO_LONG; + } + return rc; +} + + +/** + * Converts the path to UTF-16 and sets all the return values. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. + * @param phRootDir Where to return the root handle, if applicable. + * @param pszPath The UTF-8 path. + */ +static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath) +{ + PRTUTF16 pwszPath = NULL; + size_t cwcLen; + int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, &pwszPath, 0, &cwcLen); + if (RT_SUCCESS(rc)) + { + if (cwcLen < _32K - 1) + { + pNtName->Buffer = pwszPath; + pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2); + *phRootDir = NULL; + return VINF_SUCCESS; + } + + RTUtf16Free(pwszPath); + rc = VERR_FILENAME_TOO_LONG; + } + return rc; +} + + +/** + * Converts a path to NT format and encoding. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. + * @param phRootDir Where to return the root handle, if applicable. + * @param pszPath The UTF-8 path. + */ +static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath) +{ + static char const s_szPrefixUnc[] = "\\??\\UNC\\"; + static char const s_szPrefix[] = "\\??\\"; + + /* + * Very simple conversion of a win32-like path into an NT path. + */ + const char *pszPrefix = s_szPrefix; + size_t cchPrefix = sizeof(s_szPrefix) - 1; + size_t cchSkip = 0; + + if ( RTPATH_IS_SLASH(pszPath[0]) + && RTPATH_IS_SLASH(pszPath[1]) + && !RTPATH_IS_SLASH(pszPath[2]) + && pszPath[2]) + { + if ( pszPath[2] == '?' + && RTPATH_IS_SLASH(pszPath[3])) + return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath); + +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */ + if ( pszPath[2] == '!' + && RTPATH_IS_SLASH(pszPath[3])) + return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3); +#endif + + if ( pszPath[2] == '.' + && RTPATH_IS_SLASH(pszPath[3])) + { + /* + * Device path. + * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows. + */ + cchSkip = 4; + } + else + { + /* UNC */ + pszPrefix = s_szPrefixUnc; + cchPrefix = sizeof(s_szPrefixUnc) - 1; + cchSkip = 2; + } + } + + /* + * Straighten out all .. and uncessary . references and convert slashes. + */ + char szPath[RTPATH_MAX]; + int rc = RTPathAbs(pszPath, &szPath[cchPrefix - cchSkip], sizeof(szPath) - (cchPrefix - cchSkip)); + if (RT_FAILURE(rc)) + return rc; + + /* + * Add prefix and convert it to UTF16. + */ + memcpy(szPath, pszPrefix, cchPrefix); + return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath); +} + + +/** + * Frees the native path and root handle. + * + * @param pNtName The NT path after a successful rtNtPathToNative + * call. + * @param phRootDir The root handle variable after a + * rtNtPathToNative. + */ +void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir) +{ + RTUtf16Free(pNtName->Buffer); + pNtName->Buffer = NULL; +} + + +/** + * Wrapper around NtCreateFile. + * + * @returns IPRT status code. + * @param pszPath The UTF-8 path. + * @param fDesiredAccess See NtCreateFile. + * @param fFileAttribs See NtCreateFile. + * @param fShareAccess See NtCreateFile. + * @param fCreateDisposition See NtCreateFile. + * @param fCreateOptions See NtCreateFile. + * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see + * NtCreateFile and InitializeObjectAttributes. + * @param phHandle Where to return the handle. + * @param puAction Where to return the action taken. Optional. + */ +int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, + ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + PHANDLE phHandle, PULONG_PTR puAction) +{ + *phHandle = MY_INVALID_HANDLE_VALUE; + + HANDLE hRootDir; + UNICODE_STRING NtName; + int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath); + if (RT_SUCCESS(rc)) + { + HANDLE hFile = MY_INVALID_HANDLE_VALUE; + IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; + OBJECT_ATTRIBUTES ObjAttr; + InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL); + + NTSTATUS rcNt = NtCreateFile(&hFile, + fDesiredAccess, + &ObjAttr, + &Ios, + NULL /* AllocationSize*/, + fFileAttribs, + fShareAccess, + fCreateDisposition, + fCreateOptions, + NULL /*EaBuffer*/, + 0 /*EaLength*/); + if (NT_SUCCESS(rcNt)) + { + if (puAction) + *puAction = Ios.Information; + *phHandle = hFile; + rc = VINF_SUCCESS; + } + else + rc = RTErrConvertFromNtStatus(rcNt); + rtNtPathFreeNative(&NtName, &hRootDir); + } + return rc; +} + + +/** + * Wrapper around NtCreateFile. + * + * @returns IPRT status code. + * @param pszPath The UTF-8 path. + * @param fDesiredAccess See NtCreateFile. + * @param fFileAttribs See NtCreateFile. + * @param fShareAccess See NtCreateFile. + * @param fCreateDisposition See NtCreateFile. + * @param fCreateOptions See NtCreateFile. + * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see + * NtCreateFile and InitializeObjectAttributes. + * @param phHandle Where to return the handle. + * @param pfObjDir If not NULL, the variable pointed to will be set + * to @c true if we opened an object directory and + * @c false if we opened an directory file (normal + * directory). + */ +int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions, + ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir) +{ + *phHandle = MY_INVALID_HANDLE_VALUE; + + HANDLE hRootDir; + UNICODE_STRING NtName; + int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath); + if (RT_SUCCESS(rc)) + { + HANDLE hFile = MY_INVALID_HANDLE_VALUE; + IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; + OBJECT_ATTRIBUTES ObjAttr; + InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL); + + NTSTATUS rcNt = NtCreateFile(&hFile, + fDesiredAccess, + &ObjAttr, + &Ios, + NULL /* AllocationSize*/, + FILE_ATTRIBUTE_NORMAL, + fShareAccess, + FILE_OPEN, + fCreateOptions, + NULL /*EaBuffer*/, + 0 /*EaLength*/); + if (NT_SUCCESS(rcNt)) + { + if (pfObjDir) + *pfObjDir = false; + *phHandle = hFile; + rc = VINF_SUCCESS; + } +#ifdef IPRT_WITH_NT_PATH_PASSTHRU + else if ( pfObjDir + && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH) + && RTPATH_IS_SLASH(pszPath[0]) + && RTPATH_IS_SLASH(pszPath[1]) + && pszPath[2] == '!' + && RTPATH_IS_SLASH(pszPath[3])) + { + /* Strip trailing slash. */ + if ( NtName.Length > 2 + && RTPATH_IS_SLASH(NtName.Buffer[(NtName.Length / 2) - 1])) + NtName.Length -= 2; + + /* Rought conversion of the access flags. */ + ULONG fObjDesiredAccess = 0; + if (fDesiredAccess & (GENERIC_ALL | STANDARD_RIGHTS_ALL)) + fObjDesiredAccess = DIRECTORY_ALL_ACCESS; + else + { + if (fDesiredAccess & (FILE_GENERIC_WRITE | GENERIC_WRITE | STANDARD_RIGHTS_WRITE)) + fObjDesiredAccess |= DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_OBJECT; + if ( (fDesiredAccess & (FILE_LIST_DIRECTORY | FILE_GENERIC_READ | GENERIC_READ | STANDARD_RIGHTS_READ)) + || !fObjDesiredAccess) + fObjDesiredAccess |= DIRECTORY_QUERY | FILE_LIST_DIRECTORY; + } + + rcNt = NtOpenDirectoryObject(&hFile, fObjDesiredAccess, &ObjAttr); + if (NT_SUCCESS(rcNt)) + { + *pfObjDir = true; + *phHandle = hFile; + rc = VINF_SUCCESS; + } + else + rc = RTErrConvertFromNtStatus(rcNt); + } +#endif + else + rc = RTErrConvertFromNtStatus(rcNt); + rtNtPathFreeNative(&NtName, &hRootDir); + } + return rc; +} + + +/** + * Closes an handled open by rtNtPathOpen. + * + * @returns IPRT status code + * @param hHandle The handle value. + */ +int rtNtPathClose(HANDLE hHandle) +{ + NTSTATUS rcNt = NtClose(hHandle); + if (NT_SUCCESS(rcNt)) + return VINF_SUCCESS; + return RTErrConvertFromNtStatus(rcNt); +} + diff --git a/src/VBox/Runtime/r3/os2/filelock-os2.cpp b/src/VBox/Runtime/r3/os2/filelock-os2.cpp index 8646ecba..21839947 100644 --- a/src/VBox/Runtime/r3/os2/filelock-os2.cpp +++ b/src/VBox/Runtime/r3/os2/filelock-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/os2/mp-os2.cpp b/src/VBox/Runtime/r3/os2/mp-os2.cpp index 00260ca0..78e22a87 100644 --- a/src/VBox/Runtime/r3/os2/mp-os2.cpp +++ b/src/VBox/Runtime/r3/os2/mp-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/os2/pipe-os2.cpp b/src/VBox/Runtime/r3/os2/pipe-os2.cpp index 729f09b3..e5832c4e 100644 --- a/src/VBox/Runtime/r3/os2/pipe-os2.cpp +++ b/src/VBox/Runtime/r3/os2/pipe-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -28,75 +28,1005 @@ /******************************************************************************* * Header Files * *******************************************************************************/ +#define INCL_ERRORS +#define INCL_DOSSEMAPHORES +#include <os2.h> + #include <iprt/pipe.h> #include "internal/iprt.h" +#include <iprt/asm.h> #include <iprt/assert.h> +#include <iprt/critsect.h> #include <iprt/err.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/poll.h> +#include <iprt/process.h> +#include <iprt/thread.h> +#include <iprt/time.h> +#include "internal/pipe.h" +#include "internal/magics.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** The pipe buffer size we prefer. */ +#define RTPIPE_OS2_SIZE _32K + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +typedef struct RTPIPEINTERNAL +{ + /** Magic value (RTPIPE_MAGIC). */ + uint32_t u32Magic; + /** The pipe handle. */ + HPIPE hPipe; + /** Set if this is the read end, clear if it's the write end. */ + bool fRead; + /** Whether the pipe is in blocking or non-blocking mode. */ + bool fBlocking; + /** Set if the pipe is broken. */ + bool fBrokenPipe; + /** Usage counter. */ + uint32_t cUsers; + + /** The event semaphore associated with the pipe. */ + HEV hev; + /** The handle of the poll set currently polling on this pipe. + * We can only have one poller at the time (lazy bird). */ + RTPOLLSET hPollSet; + /** Critical section protecting the above members. + * (Taking the lazy/simple approach.) */ + RTCRITSECT CritSect; + +} RTPIPEINTERNAL; + + +/** + * Ensures that the pipe has a semaphore associated with it. + * + * @returns VBox status code. + * @param pThis The pipe. + */ +static int rtPipeOs2EnsureSem(RTPIPEINTERNAL *pThis) +{ + if (pThis->hev != NULLHANDLE) + return VINF_SUCCESS; + + HEV hev; + APIRET orc = DosCreateEventSem(NULL, &hev, DC_SEM_SHARED, FALSE); + if (orc == NO_ERROR) + { + orc = DosSetNPipeSem(pThis->hPipe, (HSEM)hev, 1); + if (orc == NO_ERROR) + { + pThis->hev = hev; + return VINF_SUCCESS; + } + + DosCloseEventSem(hev); + } + return RTErrConvertFromOS2(orc); +} RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags) { - return VERR_NOT_IMPLEMENTED; + AssertPtrReturn(phPipeRead, VERR_INVALID_POINTER); + AssertPtrReturn(phPipeWrite, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTPIPE_C_VALID_MASK), VERR_INVALID_PARAMETER); + + /* + * Try create and connect a pipe pair. + */ + APIRET orc; + HPIPE hPipeR; + HFILE hPipeW; + int rc; + for (;;) + { + static volatile uint32_t g_iNextPipe = 0; + char szName[128]; + RTStrPrintf(szName, sizeof(szName), "\\pipe\\iprt-pipe-%u-%u", RTProcSelf(), ASMAtomicIncU32(&g_iNextPipe)); + + /* + * Create the read end of the pipe. + */ + ULONG fPipeMode = 1 /*instance*/ | NP_TYPE_BYTE | NP_READMODE_BYTE | NP_NOWAIT; + ULONG fOpenMode = NP_ACCESS_DUPLEX | NP_WRITEBEHIND; + if (fFlags & RTPIPE_C_INHERIT_READ) + fOpenMode |= NP_INHERIT; + else + fOpenMode |= NP_NOINHERIT; + orc = DosCreateNPipe((PSZ)szName, &hPipeR, fOpenMode, fPipeMode, RTPIPE_OS2_SIZE, RTPIPE_OS2_SIZE, NP_DEFAULT_WAIT); + if (orc == NO_ERROR) + { + orc = DosConnectNPipe(hPipeR); + if (orc == ERROR_PIPE_NOT_CONNECTED || orc == NO_ERROR) + { + /* + * Connect to the pipe (the write end), attach sem below. + */ + ULONG ulAction = 0; + ULONG fOpenW = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + ULONG fModeW = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_FAIL_ON_ERROR; + if (!(fFlags & RTPIPE_C_INHERIT_WRITE)) + fModeW |= OPEN_FLAGS_NOINHERIT; + orc = DosOpen((PSZ)szName, &hPipeW, &ulAction, 0 /*cbFile*/, FILE_NORMAL, + fOpenW, fModeW, NULL /*peaop2*/); + if (orc == NO_ERROR) + break; + } + DosClose(hPipeR); + } + if ( orc != ERROR_PIPE_BUSY /* already exist - compatible */ + && orc != ERROR_ACCESS_DENIED /* already exist - incompatible (?) */) + return RTErrConvertFromOS2(orc); + /* else: try again with a new name */ + } + + /* + * Create the two handles. + */ + RTPIPEINTERNAL *pThisR = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL)); + if (pThisR) + { + RTPIPEINTERNAL *pThisW = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL)); + if (pThisW) + { + /* Crit sects. */ + rc = RTCritSectInit(&pThisR->CritSect); + if (RT_SUCCESS(rc)) + { + rc = RTCritSectInit(&pThisW->CritSect); + if (RT_SUCCESS(rc)) + { + /* Initialize the structures. */ + pThisR->u32Magic = RTPIPE_MAGIC; + pThisW->u32Magic = RTPIPE_MAGIC; + pThisR->hPipe = hPipeR; + pThisW->hPipe = hPipeW; + pThisR->hev = NULLHANDLE; + pThisW->hev = NULLHANDLE; + pThisR->fRead = true; + pThisW->fRead = false; + pThisR->fBlocking = false; + pThisW->fBlocking = true; + //pThisR->fBrokenPipe = false; + //pThisW->fBrokenPipe = false; + //pThisR->cUsers = 0; + //pThisW->cUsers = 0; + pThisR->hPollSet = NIL_RTPOLLSET; + pThisW->hPollSet = NIL_RTPOLLSET; + + *phPipeRead = pThisR; + *phPipeWrite = pThisW; + return VINF_SUCCESS; + } + + RTCritSectDelete(&pThisR->CritSect); + } + RTMemFree(pThisW); + } + else + rc = VERR_NO_MEMORY; + RTMemFree(pThisR); + } + else + rc = VERR_NO_MEMORY; + + /* Don't call DosDisConnectNPipe! */ + DosClose(hPipeW); + DosClose(hPipeR); + return rc; } RTDECL(int) RTPipeClose(RTPIPE hPipe) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + if (pThis == NIL_RTPIPE) + return VINF_SUCCESS; + AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + + /* + * Do the cleanup. + */ + AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE); + RTCritSectEnter(&pThis->CritSect); + Assert(pThis->cUsers == 0); + + /* Don't call DosDisConnectNPipe! */ + DosClose(pThis->hPipe); + pThis->hPipe = (HPIPE)-1; + + if (pThis->hev != NULLHANDLE) + { + DosCloseEventSem(pThis->hev); + pThis->hev = NULLHANDLE; + } + + RTCritSectLeave(&pThis->CritSect); + RTCritSectDelete(&pThis->CritSect); + + RTMemFree(pThis); + + return VINF_SUCCESS; } RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags) { - return VERR_NOT_IMPLEMENTED; -} + AssertPtrReturn(phPipe, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTPIPE_N_VALID_MASK), VERR_INVALID_PARAMETER); + AssertReturn(!!(fFlags & RTPIPE_N_READ) != !!(fFlags & RTPIPE_N_WRITE), VERR_INVALID_PARAMETER); + + /* + * Get and validate the pipe handle info. + */ + HPIPE hNative = (HPIPE)hNativePipe; + ULONG ulType = 0; + ULONG ulAttr = 0; + APIRET orc = DosQueryHType(hNative, &ulType, &ulAttr); + AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), RTErrConvertFromOS2(orc)); + AssertReturn((ulType & 0x7) == HANDTYPE_PIPE, VERR_INVALID_HANDLE); +#if 0 + union + { + PIPEINFO PipeInfo; + uint8_t abPadding[sizeof(PIPEINFO) + 127]; + } Buf; + orc = DosQueryNPipeInfo(hNative, 1, &Buf, sizeof(Buf)); + if (orc != NO_ERROR) + { + /* Sorry, anonymous pips are not supported. */ + AssertMsgFailed(("%d\n", orc)); + return VERR_INVALID_HANDLE; + } + AssertReturn(Buf.PipeInfo.cbMaxInst == 1, VERR_INVALID_HANDLE); +#endif + + ULONG fPipeState = 0; + orc = DosQueryNPHState(hNative, &fPipeState); + if (orc != NO_ERROR) + { + /* Sorry, anonymous pips are not supported. */ + AssertMsgFailed(("%d\n", orc)); + return VERR_INVALID_HANDLE; + } + AssertReturn(!(fPipeState & NP_TYPE_MESSAGE), VERR_INVALID_HANDLE); + AssertReturn(!(fPipeState & NP_READMODE_MESSAGE), VERR_INVALID_HANDLE); + AssertReturn((fPipeState & 0xff) == 1, VERR_INVALID_HANDLE); + + ULONG fFileState = 0; + orc = DosQueryFHState(hNative, &fFileState); + AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), VERR_INVALID_HANDLE); + AssertMsgReturn( (fFileState & 0x3) == (fFlags & RTPIPE_N_READ ? OPEN_ACCESS_READONLY : OPEN_ACCESS_WRITEONLY) + || (fFileState & 0x3) == OPEN_ACCESS_READWRITE + , ("%#x\n", fFileState), VERR_INVALID_HANDLE); + + /* + * Looks kind of OK. Fix the inherit flag. + */ + orc = DosSetFHState(hNative, (fFileState & (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE)) + | (fFlags & RTPIPE_N_INHERIT ? 0 : OPEN_FLAGS_NOINHERIT)); + AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), RTErrConvertFromOS2(orc)); + + + /* + * Create a handle so we can try rtPipeQueryInfo on it + * and see if we need to duplicate it to make that call work. + */ + RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL)); + if (!pThis) + return VERR_NO_MEMORY; + int rc = RTCritSectInit(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + pThis->u32Magic = RTPIPE_MAGIC; + pThis->hPipe = hNative; + pThis->hev = NULLHANDLE; + pThis->fRead = !!(fFlags & RTPIPE_N_READ); + pThis->fBlocking = !(fPipeState & NP_NOWAIT); + //pThis->fBrokenPipe = false; + //pThis->cUsers = 0; + pThis->hPollSet = NIL_RTPOLLSET; + + *phPipe = pThis; + return VINF_SUCCESS; + + //RTCritSectDelete(&pThis->CritSect); + } + RTMemFree(pThis); + return rc; +} RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe) { - return -1; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, -1); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, -1); + + return (RTHCINTPTR)pThis->hPipe; +} + +/** + * Prepare blocking mode. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is + * attempted. + * + * @param pThis The pipe handle. + * + * @remarks Caller owns the critical section. + */ +static int rtPipeTryBlocking(RTPIPEINTERNAL *pThis) +{ + if (!pThis->fBlocking) + { + if (pThis->cUsers != 0) + return VERR_WRONG_ORDER; + + APIRET orc = DosSetNPHState(pThis->hPipe, NP_WAIT | NP_READMODE_BYTE); + if (orc != NO_ERROR) + { + if (orc != ERROR_BROKEN_PIPE && orc != ERROR_PIPE_NOT_CONNECTED) + return RTErrConvertFromOS2(orc); + pThis->fBrokenPipe = true; + } + pThis->fBlocking = true; + } + + pThis->cUsers++; + return VINF_SUCCESS; +} + + +/** + * Prepare non-blocking mode. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is + * attempted. + * + * @param pThis The pipe handle. + */ +static int rtPipeTryNonBlocking(RTPIPEINTERNAL *pThis) +{ + if (pThis->fBlocking) + { + if (pThis->cUsers != 0) + return VERR_WRONG_ORDER; + + APIRET orc = DosSetNPHState(pThis->hPipe, NP_NOWAIT | NP_READMODE_BYTE); + if (orc != NO_ERROR) + { + if (orc != ERROR_BROKEN_PIPE && orc != ERROR_PIPE_NOT_CONNECTED) + return RTErrConvertFromOS2(orc); + pThis->fBrokenPipe = true; + } + pThis->fBlocking = false; + } + + pThis->cUsers++; + return VINF_SUCCESS; +} + + +/** + * Checks if the read pipe has been broken. + * + * @returns true if broken, false if no. + * @param pThis The pipe handle (read). + */ +static bool rtPipeOs2IsBroken(RTPIPEINTERNAL *pThis) +{ + Assert(pThis->fRead); + +#if 0 + /* + * Query it via the semaphore. Not sure how fast this is... + */ + PIPESEMSTATE aStates[3]; RT_ZERO(aStates); + APIRET orc = DosQueryNPipeSemState(pThis->hev, &aStates[0], sizeof(aStates)); + if (orc == NO_ERROR) + { + if (aStates[0].fStatus == NPSS_CLOSE) + return true; + if (aStates[0].fStatus == NPSS_RDATA) + return false; + } + AssertMsgFailed(("%d / %d\n", orc, aStates[0].fStatus)); + + /* + * Fall back / alternative method. + */ +#endif + ULONG cbActual = 0; + ULONG ulState = 0; + AVAILDATA Avail = { 0, 0 }; + APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState); + if (orc != NO_ERROR) + { + if (orc != ERROR_PIPE_BUSY) + AssertMsgFailed(("%d\n", orc)); + return false; + } + + return ulState != NP_STATE_CONNECTED; } RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(pThis->fRead, VERR_ACCESS_DENIED); + AssertPtr(pcbRead); + AssertPtr(pvBuf); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + rc = rtPipeTryNonBlocking(pThis); + if (RT_SUCCESS(rc)) + { + RTCritSectLeave(&pThis->CritSect); + + ULONG cbActual = 0; + APIRET orc = DosRead(pThis->hPipe, pvBuf, cbToRead, &cbActual); + if (orc == NO_ERROR) + { + if (cbActual || !cbToRead || !rtPipeOs2IsBroken(pThis)) + *pcbRead = cbActual; + else + rc = VERR_BROKEN_PIPE; + } + else if (orc == ERROR_NO_DATA) + { + *pcbRead = 0; + rc = VINF_TRY_AGAIN; + } + else + rc = RTErrConvertFromOS2(orc); + + RTCritSectEnter(&pThis->CritSect); + if (rc == VERR_BROKEN_PIPE) + pThis->fBrokenPipe = true; + pThis->cUsers--; + } + else + rc = VERR_WRONG_ORDER; + RTCritSectLeave(&pThis->CritSect); + } + return rc; } RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(pThis->fRead, VERR_ACCESS_DENIED); + AssertPtr(pvBuf); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + rc = rtPipeTryBlocking(pThis); + if (RT_SUCCESS(rc)) + { + RTCritSectLeave(&pThis->CritSect); + + size_t cbTotalRead = 0; + while (cbToRead > 0) + { + ULONG cbActual = 0; + APIRET orc = DosRead(pThis->hPipe, pvBuf, cbToRead, &cbActual); + if (orc != NO_ERROR) + { + rc = RTErrConvertFromOS2(orc); + break; + } + if (!cbActual && rtPipeOs2IsBroken(pThis)) + { + rc = VERR_BROKEN_PIPE; + break; + } + + /* advance */ + pvBuf = (char *)pvBuf + cbActual; + cbTotalRead += cbActual; + cbToRead -= cbActual; + } + + if (pcbRead) + { + *pcbRead = cbTotalRead; + if ( RT_FAILURE(rc) + && cbTotalRead) + rc = VINF_SUCCESS; + } + + RTCritSectEnter(&pThis->CritSect); + if (rc == VERR_BROKEN_PIPE) + pThis->fBrokenPipe = true; + pThis->cUsers--; + } + else + rc = VERR_WRONG_ORDER; + RTCritSectLeave(&pThis->CritSect); + } + return rc; +} + + +/** + * Gets the available write buffer size of the pipe. + * + * @returns Number of bytes, 1 on failure. + * @param pThis The pipe handle. + */ +static ULONG rtPipeOs2GetSpace(RTPIPEINTERNAL *pThis) +{ + Assert(!pThis->fRead); + +#if 0 /* Not sure which is more efficient, neither are really optimal, I fear. */ + /* + * Query via semaphore state. + * This will walk the list of active named pipes... + */ + /** @todo Check how hev and hpipe are associated, if complicated, use the + * alternative method below. */ + PIPESEMSTATE aStates[3]; RT_ZERO(aStates); + APIRET orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates)); + if (orc == NO_ERROR) + { + if (aStates[0].fStatus == NPSS_WSPACE) + return aStates[0].usAvail; + if (aStates[1].fStatus == NPSS_WSPACE) + return aStates[1].usAvail; + return 0; + } + AssertMsgFailed(("%d / %d\n", orc, aStates[0].fStatus)); + +#else + /* + * Query via the pipe info. + * This will have to lookup and store the pipe name. + */ + union + { + PIPEINFO PipeInfo; + uint8_t abPadding[sizeof(PIPEINFO) + 127]; + } Buf; + APIRET orc = DosQueryNPipeInfo(pThis->hPipe, 1, &Buf, sizeof(Buf)); + if (orc == NO_ERROR) + return Buf.PipeInfo.cbOut; + AssertMsgFailed(("%d\n", orc)); +#endif + + return 1; } RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED); + AssertPtr(pcbWritten); + AssertPtr(pvBuf); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + rc = rtPipeTryNonBlocking(pThis); + if (RT_SUCCESS(rc)) + { + if (cbToWrite > 0) + { + ULONG cbActual = 0; + APIRET orc = DosWrite(pThis->hPipe, pvBuf, cbToWrite, &cbActual); + if (orc == NO_ERROR && cbActual == 0) + { + /* Retry with the request adjusted to the available buffer space. */ + ULONG cbAvail = rtPipeOs2GetSpace(pThis); + orc = DosWrite(pThis->hPipe, pvBuf, RT_MIN(cbAvail, cbToWrite), &cbActual); + } + + if (orc == NO_ERROR) + { + *pcbWritten = cbActual; + if (cbActual == 0) + rc = VINF_TRY_AGAIN; + } + else + { + rc = RTErrConvertFromOS2(orc); + if (rc == VERR_PIPE_NOT_CONNECTED) + rc = VERR_BROKEN_PIPE; + } + } + else + *pcbWritten = 0; + + if (rc == VERR_BROKEN_PIPE) + pThis->fBrokenPipe = true; + pThis->cUsers--; + } + else + rc = VERR_WRONG_ORDER; + RTCritSectLeave(&pThis->CritSect); + } + return rc; } RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED); + AssertPtr(pvBuf); + AssertPtrNull(pcbWritten); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + rc = rtPipeTryBlocking(pThis); + if (RT_SUCCESS(rc)) + { + RTCritSectLeave(&pThis->CritSect); + + size_t cbTotalWritten = 0; + while (cbToWrite > 0) + { + ULONG cbActual = 0; + APIRET orc = DosWrite(pThis->hPipe, pvBuf, cbToWrite, &cbActual); + if (orc != NO_ERROR) + { + rc = RTErrConvertFromOS2(orc); + if (rc == VERR_PIPE_NOT_CONNECTED) + rc = VERR_BROKEN_PIPE; + break; + } + pvBuf = (char const *)pvBuf + cbActual; + cbToWrite -= cbActual; + cbTotalWritten += cbActual; + } + + if (pcbWritten) + { + *pcbWritten = cbTotalWritten; + if ( RT_FAILURE(rc) + && cbTotalWritten) + rc = VINF_SUCCESS; + } + + RTCritSectEnter(&pThis->CritSect); + if (rc == VERR_BROKEN_PIPE) + pThis->fBrokenPipe = true; + pThis->cUsers--; + } + else + rc = VERR_WRONG_ORDER; + RTCritSectLeave(&pThis->CritSect); + } + return rc; } RTDECL(int) RTPipeFlush(RTPIPE hPipe) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED); + + APIRET orc = DosResetBuffer(pThis->hPipe); + if (orc != NO_ERROR) + { + int rc = RTErrConvertFromOS2(orc); + if (rc == VERR_BROKEN_PIPE) + { + RTCritSectEnter(&pThis->CritSect); + pThis->fBrokenPipe = true; + RTCritSectLeave(&pThis->CritSect); + } + return rc; + } + return VINF_SUCCESS; } RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + + uint64_t const StartMsTS = RTTimeMilliTS(); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_FAILURE(rc)) + return rc; + + rc = rtPipeOs2EnsureSem(pThis); + if (RT_SUCCESS(rc) && cMillies > 0) + { + /* Stop polling attempts if we might block. */ + if (pThis->hPollSet == NIL_RTPOLLSET) + pThis->hPollSet = (RTPOLLSET)(uintptr_t)0xbeef0042; + else + rc = VERR_WRONG_ORDER; + } + if (RT_SUCCESS(rc)) + { + for (unsigned iLoop = 0;; iLoop++) + { + /* + * Check the handle state. + */ + APIRET orc; + if (cMillies > 0) + { + ULONG ulIgnore; + orc = DosResetEventSem(pThis->hev, &ulIgnore); + AssertMsg(orc == NO_ERROR || orc == ERROR_ALREADY_RESET, ("%d\n", orc)); + } + + PIPESEMSTATE aStates[4]; RT_ZERO(aStates); + orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates)); + if (orc != NO_ERROR) + { + rc = RTErrConvertFromOS2(orc); + break; + } + int i = 0; + if (pThis->fRead) + while (aStates[i].fStatus == NPSS_WSPACE) + i++; + else + while (aStates[i].fStatus == NPSS_RDATA) + i++; + if (aStates[i].fStatus == NPSS_CLOSE) + break; + Assert(aStates[i].fStatus == NPSS_WSPACE || aStates[i].fStatus == NPSS_RDATA || aStates[i].fStatus == NPSS_EOI); + if ( aStates[i].fStatus != NPSS_EOI + && aStates[i].usAvail > 0) + break; + + /* + * Check for timeout. + */ + ULONG cMsMaxWait = SEM_INDEFINITE_WAIT; + if (cMillies != RT_INDEFINITE_WAIT) + { + uint64_t cElapsed = RTTimeMilliTS() - StartMsTS; + if (cElapsed >= cMillies) + { + rc = VERR_TIMEOUT; + break; + } + cMsMaxWait = cMillies - (uint32_t)cElapsed; + } + + /* + * Wait. + */ + RTCritSectLeave(&pThis->CritSect); + orc = DosWaitEventSem(pThis->hev, cMsMaxWait); + RTCritSectEnter(&pThis->CritSect); + if (orc != NO_ERROR && orc != ERROR_TIMEOUT && orc != ERROR_SEM_TIMEOUT ) + { + rc = RTErrConvertFromOS2(orc); + break; + } + } + + if (rc == VERR_BROKEN_PIPE) + pThis->fBrokenPipe = true; + if (cMillies > 0) + pThis->hPollSet = NIL_RTPOLLSET; + } + + RTCritSectLeave(&pThis->CritSect); + return rc; } RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable) { - return VERR_NOT_IMPLEMENTED; + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(pThis->fRead, VERR_PIPE_NOT_READ); + AssertPtrReturn(pcbReadable, VERR_INVALID_POINTER); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_FAILURE(rc)) + return rc; + + ULONG cbActual = 0; + ULONG ulState = 0; + AVAILDATA Avail = { 0, 0 }; + APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState); + if (orc == NO_ERROR) + { + if (Avail.cbpipe > 0 || ulState == NP_STATE_CONNECTED) + *pcbReadable = Avail.cbpipe; + else + rc = VERR_PIPE_NOT_CONNECTED; /*??*/ + } + else + rc = RTErrConvertFromOS2(orc); + + RTCritSectLeave(&pThis->CritSect); + return rc; } + +int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative) +{ + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + + AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER); + AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + rc = rtPipeOs2EnsureSem(pThis); + if (RT_SUCCESS(rc)) + *phNative = (RTHCINTPTR)pThis->hev; + RTCritSectLeave(&pThis->CritSect); + } + return rc; +} + + +/** + * Checks for pending events. + * + * @returns Event mask or 0. + * @param pThis The pipe handle. + * @param fEvents The desired events. + * @param fResetEvtSem Whether to reset the event semaphore. + */ +static uint32_t rtPipePollCheck(RTPIPEINTERNAL *pThis, uint32_t fEvents, bool fResetEvtSem) +{ + /* + * Reset the event semaphore if we're gonna wait. + */ + APIRET orc; + ULONG ulIgnore; + if (fResetEvtSem) + { + orc = DosResetEventSem(pThis->hev, &ulIgnore); + AssertMsg(orc == NO_ERROR || orc == ERROR_ALREADY_RESET, ("%d\n", orc)); + } + + /* + * Check for events. + */ + uint32_t fRetEvents = 0; + if (pThis->fBrokenPipe) + fRetEvents |= RTPOLL_EVT_ERROR; + else if (pThis->fRead) + { + ULONG cbActual = 0; + ULONG ulState = 0; + AVAILDATA Avail = { 0, 0 }; + orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState); + if (orc != NO_ERROR) + { + fRetEvents |= RTPOLL_EVT_ERROR; + if (orc == ERROR_BROKEN_PIPE || orc == ERROR_PIPE_NOT_CONNECTED) + pThis->fBrokenPipe = true; + } + else if (Avail.cbpipe > 0) + fRetEvents |= RTPOLL_EVT_READ; + else if (ulState != NP_STATE_CONNECTED) + { + fRetEvents |= RTPOLL_EVT_ERROR; + pThis->fBrokenPipe = true; + } + } + else + { + PIPESEMSTATE aStates[4]; RT_ZERO(aStates); + orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates)); + if (orc == NO_ERROR) + { + int i = 0; + while (aStates[i].fStatus == NPSS_RDATA) + i++; + if (aStates[i].fStatus == NPSS_CLOSE) + { + fRetEvents |= RTPOLL_EVT_ERROR; + pThis->fBrokenPipe = true; + } + else if ( aStates[i].fStatus == NPSS_WSPACE + && aStates[i].usAvail > 0) + fRetEvents |= RTPOLL_EVT_WRITE; + } + else + { + fRetEvents |= RTPOLL_EVT_ERROR; + if (orc == ERROR_BROKEN_PIPE || orc == ERROR_PIPE_NOT_CONNECTED) + pThis->fBrokenPipe = true; + } + } + + return fRetEvents & (fEvents | RTPOLL_EVT_ERROR); +} + + +uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait) +{ + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, UINT32_MAX); + + int rc = RTCritSectEnter(&pThis->CritSect); + AssertRCReturn(rc, UINT32_MAX); + + /* Check that this is the only current use of this pipe. */ + uint32_t fRetEvents; + if ( pThis->cUsers == 0 + || pThis->hPollSet == NIL_RTPOLLSET) + { + fRetEvents = rtPipePollCheck(pThis, fEvents, fNoWait); + if (!fRetEvents && !fNoWait) + { + /* Mark the set busy while waiting. */ + pThis->cUsers++; + pThis->hPollSet = hPollSet; + } + } + else + { + AssertFailed(); + fRetEvents = UINT32_MAX; + } + + RTCritSectLeave(&pThis->CritSect); + return fRetEvents; +} + + +uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents) +{ + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, 0); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0); + + int rc = RTCritSectEnter(&pThis->CritSect); + AssertRCReturn(rc, 0); + + Assert(pThis->cUsers > 0); + + /* harvest events. */ + uint32_t fRetEvents = rtPipePollCheck(pThis, fEvents, false); + + /* update counters. */ + pThis->cUsers--; + pThis->hPollSet = NIL_RTPOLLSET; + + RTCritSectLeave(&pThis->CritSect); + return fRetEvents; +} diff --git a/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp b/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp index 26ee5b49..3ee59bfc 100644 --- a/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp +++ b/src/VBox/Runtime/r3/os2/rtProcInitExePath-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/os2/sched-os2.cpp b/src/VBox/Runtime/r3/os2/sched-os2.cpp index 02a4bbd3..d6e5bce7 100644 --- a/src/VBox/Runtime/r3/os2/sched-os2.cpp +++ b/src/VBox/Runtime/r3/os2/sched-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/os2/sems-os2.cpp b/src/VBox/Runtime/r3/os2/sems-os2.cpp index d19a3246..a7ca3097 100644 --- a/src/VBox/Runtime/r3/os2/sems-os2.cpp +++ b/src/VBox/Runtime/r3/os2/sems-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/os2/systemmem-os2.cpp b/src/VBox/Runtime/r3/os2/systemmem-os2.cpp new file mode 100644 index 00000000..0f95ab24 --- /dev/null +++ b/src/VBox/Runtime/r3/os2/systemmem-os2.cpp @@ -0,0 +1,70 @@ +/* $Id: systemmem-os2.cpp $ */ +/** @file + * IPRT - RTSystemQueryTotalRam, OS/2 ring-3. + */ + +/* + * Copyright (C) 2010-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define INCL_DOSMISC +#define INCL_ERRORS +#include <os2.h> +#undef RT_MAX + +#include <iprt/system.h> +#include "internal/iprt.h" + +#include <iprt/err.h> +#include <iprt/assert.h> +#include <iprt/string.h> + + +RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb) +{ + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + + ULONG cbMem; + APIRET rc = DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &cbMem, sizeof(cbMem)); + if (rc != NO_ERROR) + return RTErrConvertFromOS2(rc); + + *pcb = cbMem; + return VINF_SUCCESS; +} + + +RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb) +{ + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + + ULONG cbAvailMem; + APIRET rc = DosQuerySysInfo(QSV_TOTAVAILMEM, QSV_TOTAVAILMEM, &cbAvailMem, sizeof(cbAvailMem)); + if (rc != NO_ERROR) + return RTErrConvertFromOS2(rc); + + *pcb = cbAvailMem; + return VINF_SUCCESS; +} + diff --git a/src/VBox/Runtime/r3/os2/thread-os2.cpp b/src/VBox/Runtime/r3/os2/thread-os2.cpp index e2efa01f..e6f20213 100644 --- a/src/VBox/Runtime/r3/os2/thread-os2.cpp +++ b/src/VBox/Runtime/r3/os2/thread-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -78,7 +78,7 @@ DECLHIDDEN(int) rtThreadNativeInit(void) } -DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread) +static void rtThreadOs2BlockSigAlarm(void) { /* * Block SIGALRM - required for timer-posix.cpp. @@ -89,6 +89,17 @@ DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread) sigemptyset(&SigSet); sigaddset(&SigSet, SIGALRM); sigprocmask(SIG_BLOCK, &SigSet, NULL); +} + + +DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void) +{ + rtThreadOs2BlockSigAlarm(); +} + + +DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread) +{ *g_ppCurThread = pThread; return VINF_SUCCESS; @@ -107,15 +118,7 @@ DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread) */ static void rtThreadNativeMain(void *pvArgs) { - /* - * Block SIGALRM - required for timer-posix.cpp. - * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling. - * It will not help much if someone creates threads directly using pthread_create. :/ - */ - sigset_t SigSet; - sigemptyset(&SigSet); - sigaddset(&SigSet, SIGALRM); - sigprocmask(SIG_BLOCK, &SigSet, NULL); + rtThreadOs2BlockSigAlarm(); /* * Call common main. diff --git a/src/VBox/Runtime/r3/path.cpp b/src/VBox/Runtime/r3/path.cpp index 591f0556..e43f5d95 100644 --- a/src/VBox/Runtime/r3/path.cpp +++ b/src/VBox/Runtime/r3/path.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/poll.cpp b/src/VBox/Runtime/r3/poll.cpp new file mode 100644 index 00000000..ea71cb43 --- /dev/null +++ b/src/VBox/Runtime/r3/poll.cpp @@ -0,0 +1,1109 @@ +/* $Id: poll.cpp $ */ +/** @file + * IPRT - Polling I/O Handles, Windows+Posix Implementation. + */ + +/* + * Copyright (C) 2010-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <iprt/cdefs.h> +#ifdef RT_OS_WINDOWS +# include <Windows.h> + +#elif defined(RT_OS_OS2) +# define INCL_BASE +# include <os2.h> +# include <limits.h> +# include <sys/socket.h> + +#else +# include <limits.h> +# include <errno.h> +# include <sys/poll.h> +#endif + +#include <iprt/poll.h> +#include "internal/iprt.h" + +#include <iprt/alloca.h> +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/mem.h> +#include <iprt/pipe.h> +#include <iprt/socket.h> +#include <iprt/string.h> +#include <iprt/thread.h> +#include <iprt/time.h> + +#include "internal/pipe.h" +#define IPRT_INTERNAL_SOCKET_POLLING_ONLY +#include "internal/socket.h" +#include "internal/magics.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** The maximum poll set size. + * @remarks To help portability, we set this to the Windows limit. We can lift + * this restriction later if it becomes necessary. */ +#define RTPOLL_SET_MAX 64 + + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Handle entry in a poll set. + */ +typedef struct RTPOLLSETHNDENT +{ + /** The handle type. */ + RTHANDLETYPE enmType; + /** The handle ID. */ + uint32_t id; + /** The events we're waiting for here. */ + uint32_t fEvents; + /** Set if this is the final entry for this handle. + * If the handle is entered more than once, this will be clear for all but + * the last entry. */ + bool fFinalEntry; + /** The handle union. */ + RTHANDLEUNION u; +} RTPOLLSETHNDENT; +/** Pointer to a handle entry. */ +typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT; + + +/** + * Poll set data. + */ +typedef struct RTPOLLSETINTERNAL +{ + /** The magic value (RTPOLLSET_MAGIC). */ + uint32_t u32Magic; + /** Set when someone is polling or making changes. */ + bool volatile fBusy; + + /** The number of allocated handles. */ + uint16_t cHandlesAllocated; + /** The number of valid handles in the set. */ + uint16_t cHandles; + +#ifdef RT_OS_WINDOWS + /** Pointer to an array of native handles. */ + HANDLE *pahNative; +#elif defined(RT_OS_OS2) + /** The semaphore records. */ + PSEMRECORD paSemRecs; + /** The multiple wait semaphore used for non-socket waits. */ + HMUX hmux; + /** os2_select template. */ + int *pafdSelect; + /** The number of sockets to monitor for read. */ + uint16_t cReadSockets; + /** The number of sockets to monitor for write. */ + uint16_t cWriteSockets; + /** The number of sockets to monitor for exceptions. */ + uint16_t cXcptSockets; + /** The number of pipes. */ + uint16_t cPipes; + /** Pointer to an array of native handles. */ + PRTHCINTPTR pahNative; +#else + /** Pointer to an array of pollfd structures. */ + struct pollfd *paPollFds; +#endif + /** Pointer to an array of handles and IDs. */ + PRTPOLLSETHNDENT paHandles; +} RTPOLLSETINTERNAL; + + + +/** + * Common worker for RTPoll and RTPollNoResume + */ +static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, uint64_t MsStart, RTMSINTERVAL cMillies, + uint32_t *pfEvents, uint32_t *pid) +{ + int rc; + + if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT)) + return VERR_DEADLOCK; + + /* + * Check for special case, RTThreadSleep... + */ + uint32_t const cHandles = pThis->cHandles; + if (cHandles == 0) + { + rc = RTThreadSleep(cMillies); + if (RT_SUCCESS(rc)) + rc = VERR_TIMEOUT; + return rc; + } + +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + /* + * Check + prepare the handles before waiting. + */ + uint32_t fEvents = 0; + bool const fNoWait = cMillies == 0; + uint32_t i; + for (i = 0; i < cHandles; i++) + { + switch (pThis->paHandles[i].enmType) + { + case RTHANDLETYPE_PIPE: + fEvents = rtPipePollStart(pThis->paHandles[i].u.hPipe, pThis, pThis->paHandles[i].fEvents, + pThis->paHandles[i].fFinalEntry, fNoWait); + break; + + case RTHANDLETYPE_SOCKET: + fEvents = rtSocketPollStart(pThis->paHandles[i].u.hSocket, pThis, pThis->paHandles[i].fEvents, + pThis->paHandles[i].fFinalEntry, fNoWait); + break; + + default: + AssertFailed(); + fEvents = UINT32_MAX; + break; + } + if (fEvents) + break; + } + if ( fEvents + || fNoWait) + { + + if (pid) + *pid = pThis->paHandles[i].id; + if (pfEvents) + *pfEvents = fEvents; + rc = !fEvents + ? VERR_TIMEOUT + : fEvents != UINT32_MAX + ? VINF_SUCCESS + : VERR_INTERNAL_ERROR_4; + + /* clean up */ + if (!fNoWait) + while (i-- > 0) + { + switch (pThis->paHandles[i].enmType) + { + case RTHANDLETYPE_PIPE: + rtPipePollDone(pThis->paHandles[i].u.hPipe, pThis->paHandles[i].fEvents, + pThis->paHandles[i].fFinalEntry, false); + break; + + case RTHANDLETYPE_SOCKET: + rtSocketPollDone(pThis->paHandles[i].u.hSocket, pThis->paHandles[i].fEvents, + pThis->paHandles[i].fFinalEntry, false); + break; + + default: + AssertFailed(); + break; + } + } + + return rc; + } + + + /* + * Wait. + */ +# ifdef RT_OS_WINDOWS + DWORD dwRc = WaitForMultipleObjectsEx(cHandles, pThis->pahNative, + FALSE /*fWaitAll */, + cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies, + TRUE /*fAlertable*/); + if ( dwRc >= WAIT_OBJECT_0 + && dwRc < WAIT_OBJECT_0 + cHandles) + rc = VERR_INTERRUPTED; + else if (dwRc == WAIT_TIMEOUT) + rc = VERR_TIMEOUT; + else if (dwRc == WAIT_IO_COMPLETION) + rc = VERR_INTERRUPTED; + else if (dwRc == WAIT_FAILED) + rc = RTErrConvertFromWin32(GetLastError()); + else + { + AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc)); + rc = VERR_INTERNAL_ERROR_5; + } + +# else /* RT_OS_OS2 */ + APIRET orc; + ULONG ulUser = 0; + uint16_t cSockets = pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets; + if (cSockets == 0) + { + /* Only pipes. */ + AssertReturn(pThis->cPipes > 0, VERR_INTERNAL_ERROR_2); + orc = DosWaitMuxWaitSem(pThis->hmux, + cMillies == RT_INDEFINITE_WAIT ? SEM_INDEFINITE_WAIT : RT_MIN(cMillies, SEM_INDEFINITE_WAIT - 1), + &ulUser); + rc = RTErrConvertFromOS2(orc); + } + else + { + int *pafdSelect = (int *)alloca(cSockets + 1); + if (pThis->cPipes == 0) + { + /* Only sockets. */ + memcpy(pafdSelect, pThis->pafdSelect, sizeof(pThis->pafdSelect[0]) * (cSockets + 1)); + rc = os2_select(pafdSelect, pThis->cReadSockets, pThis->cWriteSockets, pThis->cXcptSockets, + cMillies == RT_INDEFINITE_WAIT ? -1 : (long)RT_MIN(cMillies, LONG_MAX)); + if (rc > 0) + rc = VINF_SUCCESS; + else if (rc == 0) + rc = VERR_TIMEOUT; + else + rc = RTErrConvertFromErrno(sock_errno()); + } + else + { + /* Mix of both - taking the easy way out, not optimal, but whatever... */ + do + { + orc = DosWaitMuxWaitSem(pThis->hmux, 8, &ulUser); + if (orc != ERROR_TIMEOUT && orc != ERROR_SEM_TIMEOUT) + { + rc = RTErrConvertFromOS2(orc); + break; + } + + memcpy(pafdSelect, pThis->pafdSelect, sizeof(pThis->pafdSelect[0]) * (cSockets + 1)); + rc = os2_select(pafdSelect, pThis->cReadSockets, pThis->cWriteSockets, pThis->cXcptSockets, 8); + if (rc != 0) + { + if (rc > 0) + rc = VINF_SUCCESS; + else + rc = RTErrConvertFromErrno(sock_errno()); + break; + } + } while (cMillies == RT_INDEFINITE_WAIT || RTTimeMilliTS() - MsStart < cMillies); + } + } +# endif /* RT_OS_OS2 */ + + /* + * Get event (if pending) and do wait cleanup. + */ + bool fHarvestEvents = true; + for (i = 0; i < cHandles; i++) + { + fEvents = 0; + switch (pThis->paHandles[i].enmType) + { + case RTHANDLETYPE_PIPE: + fEvents = rtPipePollDone(pThis->paHandles[i].u.hPipe, pThis->paHandles[i].fEvents, + pThis->paHandles[i].fFinalEntry, fHarvestEvents); + break; + + case RTHANDLETYPE_SOCKET: + fEvents = rtSocketPollDone(pThis->paHandles[i].u.hSocket, pThis->paHandles[i].fEvents, + pThis->paHandles[i].fFinalEntry, fHarvestEvents); + break; + + default: + AssertFailed(); + break; + } + if ( fEvents + && fHarvestEvents) + { + Assert(fEvents != UINT32_MAX); + fHarvestEvents = false; + if (pfEvents) + *pfEvents = fEvents; + if (pid) + *pid = pThis->paHandles[i].id; + rc = VINF_SUCCESS; + } + } + +#else /* POSIX */ + + /* clear the revents. */ + uint32_t i = pThis->cHandles; + while (i-- > 0) + pThis->paPollFds[i].revents = 0; + + rc = poll(&pThis->paPollFds[0], pThis->cHandles, + cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX + ? -1 + : (int)cMillies); + if (rc == 0) + return VERR_TIMEOUT; + if (rc < 0) + return RTErrConvertFromErrno(errno); + for (i = 0; i < pThis->cHandles; i++) + if (pThis->paPollFds[i].revents) + { + if (pfEvents) + { + *pfEvents = 0; + if (pThis->paPollFds[i].revents & (POLLIN +# ifdef POLLRDNORM + | POLLRDNORM /* just in case */ +# endif +# ifdef POLLRDBAND + | POLLRDBAND /* ditto */ +# endif +# ifdef POLLPRI + | POLLPRI /* ditto */ +# endif +# ifdef POLLMSG + | POLLMSG /* ditto */ +# endif +# ifdef POLLWRITE + | POLLWRITE /* ditto */ +# endif +# ifdef POLLEXTEND + | POLLEXTEND /* ditto */ +# endif + ) + ) + *pfEvents |= RTPOLL_EVT_READ; + + if (pThis->paPollFds[i].revents & (POLLOUT +# ifdef POLLWRNORM + | POLLWRNORM /* just in case */ +# endif +# ifdef POLLWRBAND + | POLLWRBAND /* ditto */ +# endif + ) + ) + *pfEvents |= RTPOLL_EVT_WRITE; + + if (pThis->paPollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL +# ifdef POLLRDHUP + | POLLRDHUP +# endif + ) + ) + *pfEvents |= RTPOLL_EVT_ERROR; + } + if (pid) + *pid = pThis->paHandles[i].id; + return VINF_SUCCESS; + } + + AssertFailed(); + RTThreadYield(); + rc = VERR_INTERRUPTED; + +#endif /* POSIX */ + + return rc; +} + + +RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) +{ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertPtrNull(pfEvents); + AssertPtrNull(pid); + + /* + * Set the busy flag and do the job. + */ + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + int rc; + if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0) + { + do rc = rtPollNoResumeWorker(pThis, 0, cMillies, pfEvents, pid); + while (rc == VERR_INTERRUPTED); + } + else + { + uint64_t MsStart = RTTimeMilliTS(); + rc = rtPollNoResumeWorker(pThis, MsStart, cMillies, pfEvents, pid); + while (RT_UNLIKELY(rc == VERR_INTERRUPTED)) + { + if (RTTimeMilliTS() - MsStart >= cMillies) + { + rc = VERR_TIMEOUT; + break; + } + rc = rtPollNoResumeWorker(pThis, MsStart, cMillies, pfEvents, pid); + } + } + + ASMAtomicWriteBool(&pThis->fBusy, false); + + return rc; +} + + +RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) +{ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertPtrNull(pfEvents); + AssertPtrNull(pid); + + /* + * Set the busy flag and do the job. + */ + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + int rc; + if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0) + rc = rtPollNoResumeWorker(pThis, 0, cMillies, pfEvents, pid); + else + rc = rtPollNoResumeWorker(pThis, RTTimeMilliTS(), cMillies, pfEvents, pid); + + ASMAtomicWriteBool(&pThis->fBusy, false); + + return rc; +} + + +RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet) +{ + AssertPtrReturn(phPollSet, VERR_INVALID_POINTER); + RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAlloc(sizeof(RTPOLLSETINTERNAL)); + if (!pThis) + return VERR_NO_MEMORY; + + pThis->fBusy = false; + pThis->cHandles = 0; + pThis->cHandlesAllocated = 0; +#ifdef RT_OS_WINDOWS + pThis->pahNative = NULL; +#elif defined(RT_OS_OS2) + pThis->hmux = NULLHANDLE; + APIRET orc = DosCreateMuxWaitSem(NULL, &pThis->hmux, 0, NULL, DCMW_WAIT_ANY); + if (orc != NO_ERROR) + { + RTMemFree(pThis); + return RTErrConvertFromOS2(orc); + } + pThis->pafdSelect = NULL; + pThis->cReadSockets = 0; + pThis->cWriteSockets = 0; + pThis->cXcptSockets = 0; + pThis->cPipes = 0; + pThis->pahNative = NULL; +#else + pThis->paPollFds = NULL; +#endif + pThis->paHandles = NULL; + pThis->u32Magic = RTPOLLSET_MAGIC; + + *phPollSet = pThis; + return VINF_SUCCESS; +} + + +RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet) +{ + RTPOLLSETINTERNAL *pThis = hPollSet; + if (pThis == NIL_RTPOLLSET) + return VINF_SUCCESS; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC); +#ifdef RT_OS_WINDOWS + RTMemFree(pThis->pahNative); + pThis->pahNative = NULL; +#elif defined(RT_OS_OS2) + DosCloseMuxWaitSem(pThis->hmux); + pThis->hmux = NULLHANDLE; + RTMemFree(pThis->pafdSelect); + pThis->pafdSelect = NULL; + RTMemFree(pThis->pahNative); + pThis->pahNative = NULL; +#else + RTMemFree(pThis->paPollFds); + pThis->paPollFds = NULL; +#endif + RTMemFree(pThis->paHandles); + pThis->paHandles = NULL; + RTMemFree(pThis); + + return VINF_SUCCESS; +} + +#ifdef RT_OS_OS2 + +/** + * Checks if @a fd is in the specific socket subset. + * + * @returns true / false. + * @param pThis The poll set instance. + * @param iStart The index to start at. + * @param cFds The number of sockets to check. + * @param fd The socket to look for. + */ +static bool rtPollSetOs2IsSocketInSet(RTPOLLSETINTERNAL *pThis, uint16_t iStart, uint16_t cFds, int fd) +{ + int const *pfd = pThis->pafdSelect + iStart; + while (cFds-- > 0) + { + if (*pfd == fd) + return true; + pfd++; + } + return false; +} + + +/** + * Removes a socket from a select template subset. + * + * @param pThis The poll set instance. + * @param iStart The index to start at. + * @param pcSubSet The subset counter to decrement. + * @param fd The socket to remove. + */ +static void rtPollSetOs2RemoveSocket(RTPOLLSETINTERNAL *pThis, uint16_t iStart, uint16_t *pcFds, int fd) +{ + uint16_t cFds = *pcFds; + while (cFds-- > 0) + { + if (pThis->pafdSelect[iStart] == fd) + break; + iStart++; + } + AssertReturnVoid(iStart != UINT16_MAX); + + /* Note! We keep a -1 entry at the end of the set, thus the + 1. */ + memmove(&pThis->pafdSelect[iStart], + &pThis->pafdSelect[iStart + 1], + pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets + 1 - 1 - iStart); + *pcFds -= 1; + + Assert(pThis->pafdSelect[pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets] == -1); +} + + +/** + * Adds a socket to a select template subset. + * + * @param pThis The poll set instance. + * @param iInsert The insertion point. + * ASSUMED to be at the end of the subset. + * @param pcSubSet The subset counter to increment. + * @param fd The socket to add. + */ +static void rtPollSetOs2AddSocket(RTPOLLSETINTERNAL *pThis, uint16_t iInsert, uint16_t *pcFds, int fd) +{ + Assert(!rtPollSetOs2IsSocketInSet(pThis, iInsert - *pcFds, *pcFds, fd)); + + /* Note! We keep a -1 entry at the end of the set, thus the + 1. */ + memmove(&pThis->pafdSelect[iInsert + 1], + &pThis->pafdSelect[iInsert], + pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets + 1 - iInsert); + pThis->pafdSelect[iInsert] = fd; + *pcFds += 1; + + Assert(pThis->pafdSelect[pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets] == -1); +} + + +/** + * OS/2 specific RTPollSetAdd worker. + * + * @returns IPRT status code. + * @param pThis The poll set instance. + * @param i The index of the new handle (not committed). + * @param fEvents The events to poll for. + */ +static int rtPollSetOs2Add(RTPOLLSETINTERNAL *pThis, unsigned i, uint32_t fEvents) +{ + if (pThis->paHandles[i].enmType == RTHANDLETYPE_SOCKET) + { + int const fdSocket = pThis->pahNative[i]; + if ( (fEvents & RTPOLL_EVT_READ) + && rtPollSetOs2IsSocketInSet(pThis, 0, pThis->cReadSockets, fdSocket)) + rtPollSetOs2AddSocket(pThis, pThis->cReadSockets, &pThis->cReadSockets, fdSocket); + + if ( (fEvents & RTPOLL_EVT_WRITE) + && rtPollSetOs2IsSocketInSet(pThis, pThis->cReadSockets, pThis->cWriteSockets, fdSocket)) + rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cWriteSockets, fdSocket); + + if ( (fEvents & RTPOLL_EVT_ERROR) + && rtPollSetOs2IsSocketInSet(pThis, pThis->cReadSockets + pThis->cWriteSockets, pThis->cXcptSockets, fdSocket)) + rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets, + &pThis->cXcptSockets, fdSocket); + } + else if (pThis->paHandles[i].enmType == RTHANDLETYPE_PIPE) + { + SEMRECORD Rec = { (HSEM)pThis->pahNative[i], pThis->paHandles[i].id }; + APIRET orc = DosAddMuxWaitSem(pThis->hmux, &Rec); + if (orc != NO_ERROR && orc != ERROR_DUPLICATE_HANDLE) + return RTErrConvertFromOS2(orc); + pThis->cPipes++; + } + else + AssertFailedReturn(VERR_INTERNAL_ERROR_2); + return VINF_SUCCESS; +} + +#endif /* RT_OS_OS2 */ + +/** + * Grows the poll set. + * + * @returns VINF_SUCCESS or VERR_NO_MEMORY. + * @param pThis The poll set instance. + * @param cHandlesNew The new poll set size. + */ +static int rtPollSetGrow(RTPOLLSETINTERNAL *pThis, uint32_t cHandlesNew) +{ + Assert(cHandlesNew > pThis->cHandlesAllocated); + + /* The common array. */ + void *pvNew = RTMemRealloc(pThis->paHandles, cHandlesNew * sizeof(pThis->paHandles[0])); + if (!pvNew) + return VERR_NO_MEMORY; + pThis->paHandles = (PRTPOLLSETHNDENT)pvNew; + + + /* OS specific handles */ +#if defined(RT_OS_WINDOWS) + pvNew = RTMemRealloc(pThis->pahNative, cHandlesNew * sizeof(pThis->pahNative[0])); + if (!pvNew) + return VERR_NO_MEMORY; + pThis->pahNative = (HANDLE *)pvNew; + +#elif defined(RT_OS_OS2) + pvNew = RTMemRealloc(pThis->pahNative, cHandlesNew * sizeof(pThis->pahNative[0])); + if (!pvNew) + return VERR_NO_MEMORY; + pThis->pahNative = (PRTHCINTPTR)pvNew; + + pvNew = RTMemRealloc(pThis->pafdSelect, (cHandlesNew * 3 + 1) * sizeof(pThis->pafdSelect[0])); + if (!pvNew) + return VERR_NO_MEMORY; + pThis->pafdSelect = (int *)pvNew; + if (pThis->cHandlesAllocated == 0) + pThis->pafdSelect[0] = -1; + +#else + pvNew = RTMemRealloc(pThis->paPollFds, cHandlesNew * sizeof(pThis->paPollFds[0])); + if (!pvNew) + return VERR_NO_MEMORY; + pThis->paPollFds = (struct pollfd *)pvNew; + +#endif + + pThis->cHandlesAllocated = (uint16_t)cHandlesNew; + return VINF_SUCCESS; +} + + +RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id) +{ + /* + * Validate the input (tedious). + */ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); + AssertReturn(fEvents, VERR_INVALID_PARAMETER); + AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); + + if (!pHandle) + return VINF_SUCCESS; + AssertPtrReturn(pHandle, VERR_INVALID_POINTER); + AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER); + + /* + * Set the busy flag and do the job. + */ + + int rc = VINF_SUCCESS; + RTHCINTPTR hNative = -1; + RTHANDLEUNION uh; + uh.uInt = 0; + switch (pHandle->enmType) + { + case RTHANDLETYPE_PIPE: + uh.hPipe = pHandle->u.hPipe; + if (uh.hPipe == NIL_RTPIPE) + return VINF_SUCCESS; + rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative); + break; + + case RTHANDLETYPE_SOCKET: + uh.hSocket = pHandle->u.hSocket; + if (uh.hSocket == NIL_RTSOCKET) + return VINF_SUCCESS; + rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative); + break; + + case RTHANDLETYPE_FILE: + AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n")); + rc = VERR_POLL_HANDLE_NOT_POLLABLE; + break; + + case RTHANDLETYPE_THREAD: + AssertMsgFailed(("Thread handles are currently not pollable\n")); + rc = VERR_POLL_HANDLE_NOT_POLLABLE; + break; + + default: + AssertMsgFailed(("\n")); + rc = VERR_POLL_HANDLE_NOT_POLLABLE; + break; + } + if (RT_SUCCESS(rc)) + { + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + uint32_t const i = pThis->cHandles; + + /* Check that the handle ID doesn't exist already. */ + uint32_t iPrev = UINT32_MAX; + uint32_t j = i; + while (j-- > 0) + { + if (pThis->paHandles[j].id == id) + { + rc = VERR_POLL_HANDLE_ID_EXISTS; + break; + } + if ( pThis->paHandles[j].enmType == pHandle->enmType + && pThis->paHandles[j].u.uInt == uh.uInt) + iPrev = j; + } + + /* Check that we won't overflow the poll set now. */ + if ( RT_SUCCESS(rc) + && i + 1 > RTPOLL_SET_MAX) + rc = VERR_POLL_SET_IS_FULL; + + /* Grow the tables if necessary. */ + if (RT_SUCCESS(rc) && i + 1 > pThis->cHandlesAllocated) + rc = rtPollSetGrow(pThis, pThis->cHandlesAllocated + 32); + if (RT_SUCCESS(rc)) + { + /* + * Add the handles to the two parallel arrays. + */ +#ifdef RT_OS_WINDOWS + pThis->pahNative[i] = (HANDLE)hNative; +#elif defined(RT_OS_OS2) + pThis->pahNative[i] = hNative; +#else + pThis->paPollFds[i].fd = (int)hNative; + pThis->paPollFds[i].revents = 0; + pThis->paPollFds[i].events = 0; + if (fEvents & RTPOLL_EVT_READ) + pThis->paPollFds[i].events |= POLLIN; + if (fEvents & RTPOLL_EVT_WRITE) + pThis->paPollFds[i].events |= POLLOUT; + if (fEvents & RTPOLL_EVT_ERROR) + pThis->paPollFds[i].events |= POLLERR; +#endif + pThis->paHandles[i].enmType = pHandle->enmType; + pThis->paHandles[i].u = uh; + pThis->paHandles[i].id = id; + pThis->paHandles[i].fEvents = fEvents; + pThis->paHandles[i].fFinalEntry = true; + + if (iPrev != UINT32_MAX) + { + Assert(pThis->paHandles[i].fFinalEntry); + pThis->paHandles[i].fFinalEntry = false; + } + + /* + * Validations and OS specific updates. + */ +#ifdef RT_OS_WINDOWS + /* none */ +#elif defined(RT_OS_OS2) + rc = rtPollSetOs2Add(pThis, i, fEvents); +#else /* POSIX */ + if (poll(&pThis->paPollFds[i], 1, 0) < 0) + { + rc = RTErrConvertFromErrno(errno); + pThis->paPollFds[i].fd = -1; + } +#endif /* POSIX */ + + if (RT_SUCCESS(rc)) + { + /* + * Commit it to the set. + */ + pThis->cHandles++; Assert(pThis->cHandles == i + 1); + rc = VINF_SUCCESS; + } + } + } + + ASMAtomicWriteBool(&pThis->fBusy, false); + return rc; +} + + +RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id) +{ + /* + * Validate the input. + */ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); + + /* + * Set the busy flag and do the job. + */ + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; + uint32_t i = pThis->cHandles; + while (i-- > 0) + if (pThis->paHandles[i].id == id) + { + /* Save some details for the duplicate searching. */ + bool const fFinalEntry = pThis->paHandles[i].fFinalEntry; + RTHANDLETYPE const enmType = pThis->paHandles[i].enmType; + RTHANDLEUNION const uh = pThis->paHandles[i].u; +#ifdef RT_OS_OS2 + uint32_t fRemovedEvents = pThis->paHandles[i].fEvents; + RTHCINTPTR const hNative = pThis->pahNative[i]; +#endif + + /* Remove the entry. */ + pThis->cHandles--; + size_t const cToMove = pThis->cHandles - i; + if (cToMove) + { + memmove(&pThis->paHandles[i], &pThis->paHandles[i + 1], cToMove * sizeof(pThis->paHandles[i])); +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + memmove(&pThis->pahNative[i], &pThis->pahNative[i + 1], cToMove * sizeof(pThis->pahNative[i])); +#else + memmove(&pThis->paPollFds[i], &pThis->paPollFds[i + 1], cToMove * sizeof(pThis->paPollFds[i])); +#endif + } + + /* Check for duplicate and set the fFinalEntry flag. */ + if (fFinalEntry) + while (i-- > 0) + if ( pThis->paHandles[i].u.uInt == uh.uInt + && pThis->paHandles[i].enmType == enmType) + { + Assert(!pThis->paHandles[i].fFinalEntry); + pThis->paHandles[i].fFinalEntry = true; + break; + } + +#ifdef RT_OS_OS2 + /* + * Update OS/2 wait structures. + */ + uint32_t fNewEvents = 0; + i = pThis->cHandles; + while (i-- > 0) + if ( pThis->paHandles[i].u.uInt == uh.uInt + && pThis->paHandles[i].enmType == enmType) + fNewEvents |= pThis->paHandles[i].fEvents; + if (enmType == RTHANDLETYPE_PIPE) + { + pThis->cPipes--; + if (fNewEvents == 0) + { + APIRET orc = DosDeleteMuxWaitSem(pThis->hmux, (HSEM)hNative); + AssertMsg(orc == NO_ERROR, ("%d\n", orc)); + } + } + else if ( fNewEvents != (fNewEvents | fRemovedEvents) + && enmType == RTHANDLETYPE_SOCKET) + { + fRemovedEvents = fNewEvents ^ (fNewEvents | fRemovedEvents); + if (fRemovedEvents & RTPOLL_EVT_ERROR) + rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cXcptSockets, (int)hNative); + if (fRemovedEvents & RTPOLL_EVT_WRITE) + rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets, &pThis->cWriteSockets, (int)hNative); + if (fRemovedEvents & RTPOLL_EVT_READ) + rtPollSetOs2RemoveSocket(pThis, 0, &pThis->cReadSockets, (int)hNative); + } +#endif /* RT_OS_OS2 */ + rc = VINF_SUCCESS; + break; + } + + ASMAtomicWriteBool(&pThis->fBusy, false); + return rc; +} + + +RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) +{ + /* + * Validate the input. + */ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); + AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER); + + /* + * Set the busy flag and do the job. + */ + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; + uint32_t i = pThis->cHandles; + while (i-- > 0) + if (pThis->paHandles[i].id == id) + { + if (pHandle) + { + pHandle->enmType = pThis->paHandles[i].enmType; + pHandle->u = pThis->paHandles[i].u; + } + rc = VINF_SUCCESS; + break; + } + + ASMAtomicWriteBool(&pThis->fBusy, false); + return rc; +} + + +RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet) +{ + /* + * Validate the input. + */ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX); + + /* + * Set the busy flag and do the job. + */ + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX); + uint32_t cHandles = pThis->cHandles; + ASMAtomicWriteBool(&pThis->fBusy, false); + + return cHandles; +} + +RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents) +{ + /* + * Validate the input. + */ + RTPOLLSETINTERNAL *pThis = hPollSet; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); + AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); + AssertReturn(fEvents, VERR_INVALID_PARAMETER); + + /* + * Set the busy flag and do the job. + */ + AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); + + int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; + uint32_t i = pThis->cHandles; + while (i-- > 0) + if (pThis->paHandles[i].id == id) + { + if (pThis->paHandles[i].fEvents != fEvents) + { +#if defined(RT_OS_WINDOWS) + /*nothing*/ +#elif defined(RT_OS_OS2) + if (pThis->paHandles[i].enmType == RTHANDLETYPE_SOCKET) + { + uint32_t fOldEvents = 0; + uint32_t j = pThis->cHandles; + while (j-- > 0) + if ( pThis->paHandles[j].enmType == RTHANDLETYPE_SOCKET + && pThis->paHandles[j].u.uInt == pThis->paHandles[i].u.uInt + && j != i) + fOldEvents |= pThis->paHandles[j].fEvents; + uint32_t fNewEvents = fOldEvents | fEvents; + fOldEvents |= pThis->paHandles[i].fEvents; + if (fOldEvents != fEvents) + { + int const fdSocket = pThis->pahNative[i]; + uint32_t const fChangedEvents = fOldEvents ^ fNewEvents; + + if ((fChangedEvents & RTPOLL_EVT_READ) && (fNewEvents & RTPOLL_EVT_READ)) + rtPollSetOs2AddSocket(pThis, pThis->cReadSockets, &pThis->cReadSockets, fdSocket); + else if (fChangedEvents & RTPOLL_EVT_READ) + rtPollSetOs2RemoveSocket(pThis, 0, &pThis->cReadSockets, fdSocket); + + if ((fChangedEvents & RTPOLL_EVT_WRITE) && (fNewEvents & RTPOLL_EVT_WRITE)) + rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, + &pThis->cWriteSockets, fdSocket); + else if (fChangedEvents & RTPOLL_EVT_WRITE) + rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets, &pThis->cWriteSockets, fdSocket); + + if ((fChangedEvents & RTPOLL_EVT_ERROR) && (fNewEvents & RTPOLL_EVT_ERROR)) + rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets, + &pThis->cXcptSockets, fdSocket); + else if (fChangedEvents & RTPOLL_EVT_ERROR) + rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cXcptSockets, + fdSocket); + } + } +#else + pThis->paPollFds[i].events = 0; + if (fEvents & RTPOLL_EVT_READ) + pThis->paPollFds[i].events |= POLLIN; + if (fEvents & RTPOLL_EVT_WRITE) + pThis->paPollFds[i].events |= POLLOUT; + if (fEvents & RTPOLL_EVT_ERROR) + pThis->paPollFds[i].events |= POLLERR; +#endif + pThis->paHandles[i].fEvents = fEvents; + } + rc = VINF_SUCCESS; + break; + } + + ASMAtomicWriteBool(&pThis->fBusy, false); + return rc; +} + diff --git a/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp b/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp index 1536d2cb..1e74477f 100644 --- a/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp +++ b/src/VBox/Runtime/r3/posix/RTFileQueryFsSizes-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp b/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp index aa12323b..ef5b4bc9 100644 --- a/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp +++ b/src/VBox/Runtime/r3/posix/RTHandleGetStandard-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -32,7 +32,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> -#include <sys/fcntl.h> #include <fcntl.h> #ifdef _MSC_VER # include <io.h> diff --git a/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp b/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp index 4e2e116d..12fff20f 100644 --- a/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp +++ b/src/VBox/Runtime/r3/posix/RTMpGetCount-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp b/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp index d39fd6c6..144f54a7 100644 --- a/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp +++ b/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp b/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp index b37d921e..6fe59a63 100644 --- a/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp +++ b/src/VBox/Runtime/r3/posix/RTSystemQueryOSInfo-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp b/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp index 96915fea..5f75e60e 100644 --- a/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp +++ b/src/VBox/Runtime/r3/posix/RTTimeNow-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp b/src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp new file mode 100644 index 00000000..2aca436c --- /dev/null +++ b/src/VBox/Runtime/r3/posix/allocex-r3-posix.cpp @@ -0,0 +1,109 @@ +/* $Id: allocex-r3-posix.cpp $ */ +/** @file + * IPRT - Memory Allocation, Extended Alloc Workers, posix. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define RTMEM_NO_WRAP_TO_EF_APIS +#include <iprt/mem.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/string.h> +#include "../allocex.h" + +#include <sys/mman.h> + + +DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) +{ + AssertReturn(cbAlloc < _64K, VERR_NO_MEMORY); + + /* + * Try with every possible address hint since the possible range is very limited. + */ + int fProt = PROT_READ | PROT_WRITE | (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PROT_EXEC : 0); + uintptr_t uAddr = 0x1000; + uintptr_t uAddrLast = _64K - uAddr - cbAlloc; + while (uAddr <= uAddrLast) + { + void *pv = mmap((void *)uAddr, cbAlloc, fProt, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (pv && (uintptr_t)pv <= uAddrLast) + { + *ppv = pv; + return VINF_SUCCESS; + } + + if (pv) + { + munmap(pv, cbAlloc); + pv = NULL; + } + uAddr += _4K; + } + + return VERR_NO_MEMORY; +} + + +DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) +{ + int fProt = PROT_READ | PROT_WRITE | (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PROT_EXEC : 0); +#if ARCH_BITS == 32 + void *pv = mmap(NULL, cbAlloc, fProt, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (pv) + { + *ppv = pv; + return VINF_SUCCESS; + } + return VERR_NO_MEMORY; + +#elif defined(RT_OS_LINUX) +# ifdef MAP_32BIT + void *pv = mmap(NULL, cbAlloc, fProt, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); + if (pv) + { + *ppv = pv; + return VINF_SUCCESS; + } +# endif + + /** @todo On linux, we need an accurate hint. Since I don't need this branch of + * the code right now, I won't bother starting to parse + * /proc/curproc/mmap right now... */ +#else +#endif + return VERR_NOT_SUPPORTED; +} + + +DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags) +{ + munmap(pv, cb); +} + diff --git a/src/VBox/Runtime/r3/posix/dir-posix.cpp b/src/VBox/Runtime/r3/posix/dir-posix.cpp index d12cee31..db402d9e 100644 --- a/src/VBox/Runtime/r3/posix/dir-posix.cpp +++ b/src/VBox/Runtime/r3/posix/dir-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,7 +33,6 @@ #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/fcntl.h> #include <fcntl.h> #include <dirent.h> #include <stdio.h> @@ -53,7 +52,7 @@ #include "internal/fs.h" #include "internal/path.h" -#if !defined(RT_OS_SOLARIS) +#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_HAIKU) # define HAVE_DIRENT_D_TYPE 1 #endif @@ -193,6 +192,26 @@ RTDECL(int) RTDirFlush(const char *pszPath) } +size_t rtDirNativeGetStructSize(const char *pszPath) +{ + long cbNameMax = pathconf(pszPath, _PC_NAME_MAX); +# ifdef NAME_MAX + if (cbNameMax < NAME_MAX) /* This is plain paranoia, but it doesn't hurt. */ + cbNameMax = NAME_MAX; +# endif +# ifdef _XOPEN_NAME_MAX + if (cbNameMax < _XOPEN_NAME_MAX) /* Ditto. */ + cbNameMax = _XOPEN_NAME_MAX; +# endif + size_t cbDir = RT_OFFSETOF(RTDIR, Data.d_name[cbNameMax + 1]); + if (cbDir < sizeof(RTDIR)) /* Ditto. */ + cbDir = sizeof(RTDIR); + cbDir = RT_ALIGN_Z(cbDir, 8); + + return cbDir; +} + + int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) { NOREF(pszPathBuf); /* only used on windows */ @@ -208,11 +227,9 @@ int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) if (pDir->pDir) { /* - * Init data. + * Init data (allocated as all zeros). */ - pDir->fDataUnread = false; - memset(&pDir->Data, 0, RT_OFFSETOF(RTDIR, Data.d_name)); /* not strictly necessary */ - memset(&pDir->Data.d_name[0], 0, pDir->cbMaxName); + pDir->fDataUnread = false; /* spelling it out */ } else rc = RTErrConvertFromErrno(errno); diff --git a/src/VBox/Runtime/r3/posix/env-posix.cpp b/src/VBox/Runtime/r3/posix/env-posix.cpp index 3134d764..cd4fdb16 100644 --- a/src/VBox/Runtime/r3/posix/env-posix.cpp +++ b/src/VBox/Runtime/r3/posix/env-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -46,13 +46,19 @@ #include "internal/alignmentchecks.h" +RTDECL(bool) RTEnvExistsBad(const char *pszVar) +{ + return RTEnvGetBad(pszVar) != NULL; +} + + RTDECL(bool) RTEnvExist(const char *pszVar) { - return RTEnvGet(pszVar) != NULL; + return RTEnvExistsBad(pszVar); } -RTDECL(const char *) RTEnvGet(const char *pszVar) +RTDECL(const char *) RTEnvGetBad(const char *pszVar) { IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */ const char *pszValue = getenv(pszVar); @@ -61,7 +67,13 @@ RTDECL(const char *) RTEnvGet(const char *pszVar) } -RTDECL(int) RTEnvPut(const char *pszVarEqualValue) +RTDECL(const char *) RTEnvGet(const char *pszVar) +{ + return RTEnvGetBad(pszVar); +} + + +RTDECL(int) RTEnvPutBad(const char *pszVarEqualValue) { /** @todo putenv is a source memory leaks. deal with this on a per system basis. */ if (!putenv((char *)pszVarEqualValue)) @@ -69,7 +81,14 @@ RTDECL(int) RTEnvPut(const char *pszVarEqualValue) return RTErrConvertFromErrno(errno); } -RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue) + +RTDECL(int) RTEnvPut(const char *pszVarEqualValue) +{ + return RTEnvPutBad(pszVarEqualValue); +} + + +RTDECL(int) RTEnvSetBad(const char *pszVar, const char *pszValue) { #if defined(_MSC_VER) /* make a local copy and feed it to putenv. */ @@ -98,7 +117,12 @@ RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue) } -RTDECL(int) RTEnvUnset(const char *pszVar) +RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue) +{ + return RTEnvSetBad(pszVar, pszValue); +} + +RTDECL(int) RTEnvUnsetBad(const char *pszVar) { AssertReturn(!strchr(pszVar, '='), VERR_INVALID_PARAMETER); @@ -131,3 +155,8 @@ RTDECL(int) RTEnvUnset(const char *pszVar) return RTErrConvertFromErrno(errno); } +RTDECL(int) RTEnvUnset(const char *pszVar) +{ + return RTEnvUnsetBad(pszVar); +} + diff --git a/src/VBox/Runtime/r3/posix/fileaio-posix.cpp b/src/VBox/Runtime/r3/posix/fileaio-posix.cpp index fe7b8d05..f14e800e 100644 --- a/src/VBox/Runtime/r3/posix/fileaio-posix.cpp +++ b/src/VBox/Runtime/r3/posix/fileaio-posix.cpp @@ -122,6 +122,8 @@ typedef struct RTFILEAIOCTXINTERNAL volatile bool fWokenUp; /** Flag whether the thread is currently waiting in the syscall. */ volatile bool fWaiting; + /** Flags given during creation. */ + uint32_t fFlags; /** Magic value (RTFILEAIOCTX_MAGIC). */ uint32_t u32Magic; /** Flag whether the thread was woken up due to a internal event. */ @@ -522,12 +524,14 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered) } -RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags) { PRTFILEAIOCTXINTERNAL pCtxInt; unsigned cReqsWaitMax; AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); if (cAioReqsMax == RTFILEAIO_UNLIMITED_REQS) return VERR_OUT_OF_RANGE; @@ -550,6 +554,7 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; pCtxInt->cMaxRequests = cAioReqsMax; pCtxInt->cReqsWaitMax = cReqsWaitMax; + pCtxInt->fFlags = fFlags; *phAioCtx = (RTFILEAIOCTX)pCtxInt; return VINF_SUCCESS; @@ -871,7 +876,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL int32_t cRequestsWaiting = ASMAtomicReadS32(&pCtxInt->cRequests); - if (RT_UNLIKELY(cRequestsWaiting <= 0)) + if ( RT_UNLIKELY(cRequestsWaiting <= 0) + && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS)) return VERR_FILE_AIO_NO_REQUEST; if (RT_UNLIKELY(cMinReqs > (uint32_t)cRequestsWaiting)) diff --git a/src/VBox/Runtime/r3/posix/fileio-posix.cpp b/src/VBox/Runtime/r3/posix/fileio-posix.cpp index b77ff050..1af29184 100644 --- a/src/VBox/Runtime/r3/posix/fileio-posix.cpp +++ b/src/VBox/Runtime/r3/posix/fileio-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -34,7 +34,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> -#include <sys/fcntl.h> #include <fcntl.h> #ifdef _MSC_VER # include <io.h> @@ -712,6 +711,19 @@ RTR3DECL(int) RTFileSetMode(RTFILE hFile, RTFMODE fMode) } +RTDECL(int) RTFileSetOwner(RTFILE hFile, uint32_t uid, uint32_t gid) +{ + uid_t uidNative = uid != NIL_RTUID ? (uid_t)uid : (uid_t)-1; + AssertReturn(uid == uidNative, VERR_INVALID_PARAMETER); + gid_t gidNative = gid != NIL_RTGID ? (gid_t)gid : (gid_t)-1; + AssertReturn(gid == gidNative, VERR_INVALID_PARAMETER); + + if (fchown(RTFileToNative(hFile), uidNative, gidNative)) + return RTErrConvertFromErrno(errno); + return VINF_SUCCESS; +} + + RTR3DECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename) { /* diff --git a/src/VBox/Runtime/r3/posix/fileio2-posix.cpp b/src/VBox/Runtime/r3/posix/fileio2-posix.cpp index 47c13697..33e10e35 100644 --- a/src/VBox/Runtime/r3/posix/fileio2-posix.cpp +++ b/src/VBox/Runtime/r3/posix/fileio2-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -46,16 +46,15 @@ #if defined(RT_OS_OS2) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006) # include <io.h> #endif -#ifdef RT_OS_L4 -/* This is currently ifdef'ed out in the relevant L4 header file */ -/* Same as `utimes', but takes an open file descriptor instead of a name. */ -extern int futimes(int __fd, __const struct timeval __tvp[2]) __THROW; -#endif #ifdef RT_OS_SOLARIS # define futimes(filedes, timeval) futimesat(filedes, NULL, timeval) #endif +#ifdef RT_OS_HAIKU +# define USE_FUTIMENS +#endif + #include <iprt/file.h> #include <iprt/path.h> #include <iprt/assert.h> @@ -143,6 +142,30 @@ RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPE if (!pAccessTime && !pModificationTime) return VINF_SUCCESS; +#ifdef USE_FUTIMENS + struct timespec aTimespecs[2]; + if (pAccessTime && pModificationTime) + { + memcpy(&aTimespecs[0], pAccessTime, sizeof(struct timespec)); + memcpy(&aTimespecs[1], pModificationTime, sizeof(struct timespec)); + } + else + { + RTFSOBJINFO ObjInfo; + int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_UNIX); + if (RT_FAILURE(rc)) + return rc; + memcpy(&aTimespecs[0], pAccessTime ? pAccessTime : &ObjInfo.AccessTime, sizeof(struct timespec)); + memcpy(&aTimespecs[1], pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, sizeof(struct timespec)); + } + + if (futimens(RTFileToNative(hFile), aTimespecs)) + { + int rc = RTErrConvertFromErrno(errno); + Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc)); + return rc; + } +#else /* * Convert the input to timeval, getting the missing one if necessary, * and call the API which does the change. @@ -171,6 +194,7 @@ RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPE Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc)); return rc; } +#endif return VINF_SUCCESS; } diff --git a/src/VBox/Runtime/r3/posix/filelock-posix.cpp b/src/VBox/Runtime/r3/posix/filelock-posix.cpp index 266297f2..67734d63 100644 --- a/src/VBox/Runtime/r3/posix/filelock-posix.cpp +++ b/src/VBox/Runtime/r3/posix/filelock-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,7 +33,6 @@ #include <errno.h> #include <sys/types.h> #include <sys/ioctl.h> -#include <sys/fcntl.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> diff --git a/src/VBox/Runtime/r3/posix/fs-posix.cpp b/src/VBox/Runtime/r3/posix/fs-posix.cpp index fdb991b1..d5e982e0 100644 --- a/src/VBox/Runtime/r3/posix/fs-posix.cpp +++ b/src/VBox/Runtime/r3/posix/fs-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -216,6 +216,8 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType) *penmType = RTFSTYPE_JFS; else if (!strcmp("xfs", mntEnt.mnt_type)) *penmType = RTFSTYPE_XFS; + else if (!strcmp("btrfs", mntEnt.mnt_type)) + *penmType = RTFSTYPE_BTRFS; else if ( !strcmp("vfat", mntEnt.mnt_type) || !strcmp("msdos", mntEnt.mnt_type)) *penmType = RTFSTYPE_FAT; diff --git a/src/VBox/Runtime/r3/posix/fs2-posix.cpp b/src/VBox/Runtime/r3/posix/fs2-posix.cpp index 38dafcf1..5eae05a1 100644 --- a/src/VBox/Runtime/r3/posix/fs2-posix.cpp +++ b/src/VBox/Runtime/r3/posix/fs2-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,6 +33,9 @@ #include <sys/param.h> #ifndef DEV_BSIZE # include <sys/stat.h> +# if defined(RT_OS_HAIKU) && !defined(S_BLKSIZE) +# define S_BLKSIZE 512 +# endif # define DEV_BSIZE S_BLKSIZE /** @todo bird: add DEV_BSIZE to sys/param.h on OS/2. */ #endif diff --git a/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp b/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp index 61ce3578..4028eb5d 100644 --- a/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp +++ b/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -108,7 +108,8 @@ DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSy DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod) { PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod; - if (!dlclose((void *)pModNative->hNative)) + if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD) + || !dlclose((void *)pModNative->hNative)) { pModNative->hNative = (uintptr_t)0; return VINF_SUCCESS; @@ -117,3 +118,10 @@ DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod) return VERR_GENERAL_FAILURE; } + +int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod) +{ + /** @todo implement this in some sensible fashion. */ + return VERR_NOT_SUPPORTED; +} + diff --git a/src/VBox/Runtime/r3/posix/path-posix.cpp b/src/VBox/Runtime/r3/posix/path-posix.cpp index 7ad6b028..2b7adf9f 100644 --- a/src/VBox/Runtime/r3/posix/path-posix.cpp +++ b/src/VBox/Runtime/r3/posix/path-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -49,11 +49,6 @@ #include "internal/process.h" #include "internal/fs.h" -#ifdef RT_OS_L4 -# include <l4/vboxserver/vboxserver.h> -#endif - - RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath) diff --git a/src/VBox/Runtime/r3/posix/path2-posix.cpp b/src/VBox/Runtime/r3/posix/path2-posix.cpp index abc2ce29..856424d7 100644 --- a/src/VBox/Runtime/r3/posix/path2-posix.cpp +++ b/src/VBox/Runtime/r3/posix/path2-posix.cpp @@ -48,10 +48,6 @@ #include "internal/process.h" #include "internal/fs.h" -#ifdef RT_OS_L4 -# include <l4/vboxserver/vboxserver.h> -#endif - RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs) { diff --git a/src/VBox/Runtime/r3/posix/pathhost-posix.cpp b/src/VBox/Runtime/r3/posix/pathhost-posix.cpp index 5390fe57..6f75c27b 100644 --- a/src/VBox/Runtime/r3/posix/pathhost-posix.cpp +++ b/src/VBox/Runtime/r3/posix/pathhost-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -134,7 +134,7 @@ static bool rtPathConvInitIsUtf8(const char *pszCodeset) * @param pvUser1 Unused. * @param pvUser2 Unused. */ -static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser) { /* * Read the environment variable, no mercy on misconfigs here except that @@ -172,7 +172,7 @@ static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser1, void *pvUser2) g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_LOCALE; } - NOREF(pvUser1); NOREF(pvUser2); + NOREF(pvUser); return VINF_SUCCESS; } @@ -181,7 +181,7 @@ int rtPathToNative(char const **ppszNativePath, const char *pszPath, const char { *ppszNativePath = NULL; - int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL); + int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL); if (RT_SUCCESS(rc)) { if (g_fPassthruUtf8 || !*pszPath) @@ -208,7 +208,7 @@ int rtPathFromNative(const char **ppszPath, const char *pszNativePath, const cha { *ppszPath = NULL; - int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL); + int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL); if (RT_SUCCESS(rc)) { if (g_fPassthruUtf8 || !*pszNativePath) @@ -246,7 +246,7 @@ void rtPathFreeIprt(const char *pszPath, const char *pszNativePath) int rtPathFromNativeCopy(char *pszPath, size_t cbPath, const char *pszNativePath, const char *pszBasePath) { - int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL); + int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL); if (RT_SUCCESS(rc)) { if (g_fPassthruUtf8 || !*pszNativePath) @@ -266,7 +266,7 @@ int rtPathFromNativeCopy(char *pszPath, size_t cbPath, const char *pszNativePath int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath) { - int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL, NULL); + int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL); if (RT_SUCCESS(rc)) { if (g_fPassthruUtf8 || !*pszNativePath) diff --git a/src/VBox/Runtime/r3/posix/pipe-posix.cpp b/src/VBox/Runtime/r3/posix/pipe-posix.cpp index 2e006cb3..9d950de9 100644 --- a/src/VBox/Runtime/r3/posix/pipe-posix.cpp +++ b/src/VBox/Runtime/r3/posix/pipe-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -35,6 +35,7 @@ #include <iprt/assert.h> #include <iprt/err.h> #include <iprt/mem.h> +#include <iprt/poll.h> #include <iprt/string.h> #include <iprt/thread.h> #include "internal/magics.h" @@ -54,6 +55,8 @@ # include <sys/filio.h> #endif +#include "internal/pipe.h" + /******************************************************************************* * Structures and Typedefs * @@ -667,3 +670,17 @@ RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable) return rc; } + +int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative) +{ + RTPIPEINTERNAL *pThis = hPipe; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); + + AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER); + AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER); + + *phNative = pThis->fd; + return VINF_SUCCESS; +} + diff --git a/src/VBox/Runtime/r3/posix/poll-posix.cpp b/src/VBox/Runtime/r3/posix/poll-posix.cpp deleted file mode 100644 index ff124968..00000000 --- a/src/VBox/Runtime/r3/posix/poll-posix.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* $Id: poll-posix.cpp $ */ -/** @file - * IPRT - Polling I/O Handles, POSIX Implementation. - */ - -/* - * Copyright (C) 2010 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * - * The contents of this file may alternatively be used under the terms - * of the Common Development and Distribution License Version 1.0 - * (CDDL) only, as it comes in the "COPYING.CDDL" file of the - * VirtualBox OSE distribution, in which case the provisions of the - * CDDL are applicable instead of those of the GPL. - * - * You may elect to license modified versions of this file under the - * terms and conditions of either the GPL or the CDDL or both. - */ - - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#include <iprt/poll.h> -#include "internal/iprt.h" - -#include <iprt/asm.h> -#include <iprt/assert.h> -#include <iprt/err.h> -#include <iprt/mem.h> -#include <iprt/pipe.h> -#include <iprt/socket.h> -#include <iprt/string.h> -#include <iprt/thread.h> -#include <iprt/time.h> -#include "internal/magics.h" - -#include <limits.h> -#include <errno.h> -#include <sys/poll.h> - - -/******************************************************************************* -* Structures and Typedefs * -*******************************************************************************/ -/** - * Handle entry in a poll set. - */ -typedef struct RTPOLLSETHNDENT -{ - /** The handle type. */ - RTHANDLETYPE enmType; - /** The handle ID. */ - uint32_t id; - /** The handle union. */ - RTHANDLEUNION u; -} RTPOLLSETHNDENT; -/** Pointer to a handle entry. */ -typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT; - -/** - * Poll set data, POSIX. - */ -typedef struct RTPOLLSETINTERNAL -{ - /** The magic value (RTPOLLSET_MAGIC). */ - uint32_t u32Magic; - /** Set when someone is polling or making changes. */ - bool volatile fBusy; - - /** The number of valid handles in the set. */ - uint32_t cHandles; - /** The number of allocated handles. */ - uint32_t cHandlesAllocated; - - /** Pointer to an array of pollfd structures. */ - struct pollfd *paPollFds; - /** Pointer to an array of handles and IDs. */ - PRTPOLLSETHNDENT paHandles; -} RTPOLLSETINTERNAL; - - -/** - * Common worker for RTPoll and RTPollNoResume - */ -static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT)) - return VERR_DEADLOCK; - - /* clear the revents. */ - uint32_t i = pThis->cHandles; - while (i-- > 0) - pThis->paPollFds[i].revents = 0; - - int rc = poll(&pThis->paPollFds[0], pThis->cHandles, - cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX - ? -1 - : (int)cMillies); - if (rc == 0) - return VERR_TIMEOUT; - if (rc < 0) - return RTErrConvertFromErrno(errno); - - for (i = 0; i < pThis->cHandles; i++) - if (pThis->paPollFds[i].revents) - { - if (pfEvents) - { - *pfEvents = 0; - if (pThis->paPollFds[i].revents & (POLLIN -#ifdef POLLRDNORM - | POLLRDNORM /* just in case */ -#endif -#ifdef POLLRDBAND - | POLLRDBAND /* ditto */ -#endif -#ifdef POLLPRI - | POLLPRI /* ditto */ -#endif -#ifdef POLLMSG - | POLLMSG /* ditto */ -#endif -#ifdef POLLWRITE - | POLLWRITE /* ditto */ -#endif -#ifdef POLLEXTEND - | POLLEXTEND /* ditto */ -#endif - ) - ) - *pfEvents |= RTPOLL_EVT_READ; - - if (pThis->paPollFds[i].revents & (POLLOUT -#ifdef POLLWRNORM - | POLLWRNORM /* just in case */ -#endif -#ifdef POLLWRBAND - | POLLWRBAND /* ditto */ -#endif - ) - ) - *pfEvents |= RTPOLL_EVT_WRITE; - - if (pThis->paPollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL -#ifdef POLLRDHUP - | POLLRDHUP -#endif - ) - ) - *pfEvents |= RTPOLL_EVT_ERROR; - } - if (pid) - *pid = pThis->paHandles[i].id; - return VINF_SUCCESS; - } - - AssertFailed(); - RTThreadYield(); - return VERR_INTERRUPTED; -} - - -RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertPtrNull(pfEvents); - AssertPtrNull(pid); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc; - if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0) - { - do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - while (rc == VERR_INTERRUPTED); - } - else - { - uint64_t MsStart = RTTimeMilliTS(); - rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - while (RT_UNLIKELY(rc == VERR_INTERRUPTED)) - { - if (RTTimeMilliTS() - MsStart >= cMillies) - { - rc = VERR_TIMEOUT; - break; - } - rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - } - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - - return rc; -} - - -RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertPtrNull(pfEvents); - AssertPtrNull(pid); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - - ASMAtomicWriteBool(&pThis->fBusy, false); - - return rc; -} - - -RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet) -{ - AssertPtrReturn(phPollSet, VERR_INVALID_POINTER); - RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAlloc(sizeof(RTPOLLSETINTERNAL)); - if (!pThis) - return VERR_NO_MEMORY; - - pThis->u32Magic = RTPOLLSET_MAGIC; - pThis->fBusy = false; - pThis->cHandles = 0; - pThis->cHandlesAllocated = 0; - pThis->paPollFds = NULL; - pThis->paHandles = NULL; - - *phPollSet = pThis; - return VINF_SUCCESS; -} - - -RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet) -{ - RTPOLLSETINTERNAL *pThis = hPollSet; - if (pThis == NIL_RTPOLLSET) - return VINF_SUCCESS; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC); - RTMemFree(pThis->paPollFds); - pThis->paPollFds = NULL; - RTMemFree(pThis->paHandles); - pThis->paHandles = NULL; - RTMemFree(pThis); - - return VINF_SUCCESS; -} - - -RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id) -{ - /* - * Validate the input (tedious). - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); - AssertReturn(fEvents, VERR_INVALID_PARAMETER); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - - if (!pHandle) - return VINF_SUCCESS; - AssertPtrReturn(pHandle, VERR_INVALID_POINTER); - AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VINF_SUCCESS; - int fd = -1; - switch (pHandle->enmType) - { - case RTHANDLETYPE_PIPE: - if (pHandle->u.hPipe != NIL_RTPIPE) - fd = (int)RTPipeToNative(pHandle->u.hPipe); - break; - - case RTHANDLETYPE_SOCKET: - if (pHandle->u.hSocket != NIL_RTSOCKET) - fd = (int)RTSocketToNative(pHandle->u.hSocket); - break; - - case RTHANDLETYPE_FILE: - AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n")); - rc = VERR_POLL_HANDLE_NOT_POLLABLE; - break; - - case RTHANDLETYPE_THREAD: - AssertMsgFailed(("Thread handles are currently not pollable\n")); - rc = VERR_POLL_HANDLE_NOT_POLLABLE; - break; - - default: - AssertMsgFailed(("\n")); - rc = VERR_POLL_HANDLE_NOT_POLLABLE; - break; - } - if (fd != -1) - { - uint32_t const i = pThis->cHandles; - - /* Check that the handle ID doesn't exist already. */ - uint32_t j = i; - while (j-- > 0) - if (pThis->paHandles[j].id == id) - { - rc = VERR_POLL_HANDLE_ID_EXISTS; - break; - } - if (RT_SUCCESS(rc)) - { - /* Grow the tables if necessary. */ - if (i + 1 > pThis->cHandlesAllocated) - { - uint32_t const c = pThis->cHandlesAllocated + 32; - void *pvNew; - pvNew = RTMemRealloc(pThis->paHandles, c * sizeof(pThis->paHandles[0])); - if (pvNew) - { - pThis->paHandles = (PRTPOLLSETHNDENT)pvNew; - pvNew = RTMemRealloc(pThis->paPollFds, c * sizeof(pThis->paPollFds[0])); - if (pvNew) - pThis->paPollFds = (struct pollfd *)pvNew; - else - rc = VERR_NO_MEMORY; - } - else - rc = VERR_NO_MEMORY; - } - if (RT_SUCCESS(rc)) - { - /* Add it to the poll file descriptor array and call poll to - validate the event flags. */ - pThis->paPollFds[i].fd = fd; - pThis->paPollFds[i].revents = 0; - pThis->paPollFds[i].events = 0; - if (fEvents & RTPOLL_EVT_READ) - pThis->paPollFds[i].events |= POLLIN; - if (fEvents & RTPOLL_EVT_WRITE) - pThis->paPollFds[i].events |= POLLOUT; - if (fEvents & RTPOLL_EVT_ERROR) - pThis->paPollFds[i].events |= POLLERR; - - if (poll(&pThis->paPollFds[i], 1, 0) >= 0) - { - /* Add the handle info and close the transaction. */ - pThis->paHandles[i].enmType = pHandle->enmType; - pThis->paHandles[i].u = pHandle->u; - pThis->paHandles[i].id = id; - - pThis->cHandles = i + 1; - rc = VINF_SUCCESS; - } - else - { - rc = RTErrConvertFromErrno(errno); - pThis->paPollFds[i].fd = -1; - } - } - } - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - - -RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; - uint32_t i = pThis->cHandles; - while (i-- > 0) - if (pThis->paHandles[i].id == id) - { - pThis->cHandles--; - size_t const cToMove = pThis->cHandles - i; - if (cToMove) - { - memmove(&pThis->paHandles[i], &pThis->paHandles[i + 1], cToMove * sizeof(pThis->paHandles[i])); - memmove(&pThis->paPollFds[i], &pThis->paPollFds[i + 1], cToMove * sizeof(pThis->paPollFds[i])); - } - rc = VINF_SUCCESS; - break; - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - - -RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; - uint32_t i = pThis->cHandles; - while (i-- > 0) - if (pThis->paHandles[i].id == id) - { - if (pHandle) - { - pHandle->enmType = pThis->paHandles[i].enmType; - pHandle->u = pThis->paHandles[i].u; - } - rc = VINF_SUCCESS; - break; - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - - -RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, UINT32_MAX); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX); - uint32_t cHandles = pThis->cHandles; - ASMAtomicWriteBool(&pThis->fBusy, false); - - return cHandles; -} - - -RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); - AssertReturn(fEvents, VERR_INVALID_PARAMETER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; - uint32_t i = pThis->cHandles; - while (i-- > 0) - if (pThis->paHandles[i].id == id) - { - pThis->paPollFds[i].events = 0; - if (fEvents & RTPOLL_EVT_READ) - pThis->paPollFds[i].events |= POLLIN; - if (fEvents & RTPOLL_EVT_WRITE) - pThis->paPollFds[i].events |= POLLOUT; - if (fEvents & RTPOLL_EVT_ERROR) - pThis->paPollFds[i].events |= POLLERR; - rc = VINF_SUCCESS; - break; - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - diff --git a/src/VBox/Runtime/r3/posix/process-creation-posix.cpp b/src/VBox/Runtime/r3/posix/process-creation-posix.cpp index 2f8841c4..4fd2d0e2 100644 --- a/src/VBox/Runtime/r3/posix/process-creation-posix.cpp +++ b/src/VBox/Runtime/r3/posix/process-creation-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,6 +29,8 @@ * Header Files * *******************************************************************************/ #define LOG_GROUP RTLOGGROUP_PROCESS +#include <iprt/cdefs.h> + #include <unistd.h> #include <stdlib.h> #include <errno.h> @@ -37,20 +39,28 @@ #include <sys/wait.h> #include <fcntl.h> #include <signal.h> +#include <grp.h> #if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) # include <crypt.h> # include <pwd.h> # include <shadow.h> #endif + #if defined(RT_OS_LINUX) || defined(RT_OS_OS2) /* While Solaris has posix_spawn() of course we don't want to use it as * we need to have the child in a different process contract, no matter * whether it is started detached or not. */ # define HAVE_POSIX_SPAWN 1 #endif +#if defined(RT_OS_DARWIN) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 +# define HAVE_POSIX_SPAWN 1 +# endif +#endif #ifdef HAVE_POSIX_SPAWN # include <spawn.h> #endif + #ifdef RT_OS_DARWIN # include <mach-o/dyld.h> #endif @@ -297,6 +307,10 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER); AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER); +#if defined(RT_OS_OS2) + if (fFlags & RTPROC_FLAGS_DETACHED) + return VERR_PROC_DETACH_NOT_SUPPORTED; +#endif /* * Get the file descriptors for the handles we've been passed. @@ -462,20 +476,30 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg rc = posix_spawnattr_init(&Attr); if (!rc) { -# ifndef RT_OS_OS2 /* We don't need this on OS/2 and I don't recall if it's actually implemented. */ - rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP); + /* Indicate that process group and signal mask are to be changed, + and that the child should use default signal actions. */ + rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF); Assert(rc == 0); + + /* The child starts in its own process group. */ if (!rc) { rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */); Assert(rc == 0); } -# endif + + /* Unmask all signals. */ + if (!rc) + { + sigset_t SigMask; + sigemptyset(&SigMask); + rc = posix_spawnattr_setsigmask(&Attr, &SigMask); Assert(rc == 0); + } /* File changes. */ posix_spawn_file_actions_t FileActions; posix_spawn_file_actions_t *pFileActions = NULL; - if (aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) + if ((aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) && !rc) { rc = posix_spawn_file_actions_init(&FileActions); if (!rc) @@ -525,7 +549,7 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) - _Exit(0); + _Exit(0); if (phProcess) *phProcess = pid; return VINF_SUCCESS; @@ -540,15 +564,20 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg #endif { #ifdef RT_OS_SOLARIS - int templateFd = rtSolarisContractPreFork(); - if (templateFd == -1) - return VERR_OPEN_FAILED; + int templateFd = -1; + if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) + { + templateFd = rtSolarisContractPreFork(); + if (templateFd == -1) + return VERR_OPEN_FAILED; + } #endif /* RT_OS_SOLARIS */ pid = fork(); if (!pid) { #ifdef RT_OS_SOLARIS - rtSolarisContractPostForkChild(templateFd); + if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) + rtSolarisContractPostForkChild(templateFd); #endif /* RT_OS_SOLARIS */ if (!(fFlags & RTPROC_FLAGS_DETACHED)) setpgid(0, 0); /* see comment above */ @@ -557,6 +586,17 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg * Change group and user if requested. */ #if 1 /** @todo This needs more work, see suplib/hardening. */ + if (pszAsUser) + { + int ret = initgroups(pszAsUser, gid); + if (ret) + { + if (fFlags & RTPROC_FLAGS_DETACHED) + _Exit(126); + else + exit(126); + } + } if (gid != ~(gid_t)0) { if (setgid(gid)) @@ -581,6 +621,14 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg #endif /* + * Unset the signal mask. + */ + sigset_t SigMask; + sigemptyset(&SigMask); + rc = sigprocmask(SIG_SETMASK, &SigMask, NULL); + Assert(rc == 0); + + /* * Apply changes to the standard file descriptor and stuff. */ for (int i = 0; i < 3; i++) @@ -627,7 +675,8 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg exit(127); } #ifdef RT_OS_SOLARIS - rtSolarisContractPostForkParent(templateFd, pid); + if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) + rtSolarisContractPostForkParent(templateFd, pid); #endif /* RT_OS_SOLARIS */ if (pid > 0) { diff --git a/src/VBox/Runtime/r3/posix/process-posix.cpp b/src/VBox/Runtime/r3/posix/process-posix.cpp index 7b823163..01631f6d 100644 --- a/src/VBox/Runtime/r3/posix/process-posix.cpp +++ b/src/VBox/Runtime/r3/posix/process-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -188,4 +188,3 @@ RTR3DECL(int) RTProcQueryUsername(RTPROCESS hProcess, char *pszUser, size_t cbUs return rc; } - diff --git a/src/VBox/Runtime/r3/posix/rand-posix.cpp b/src/VBox/Runtime/r3/posix/rand-posix.cpp index f394d149..1d1725f1 100644 --- a/src/VBox/Runtime/r3/posix/rand-posix.cpp +++ b/src/VBox/Runtime/r3/posix/rand-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -32,7 +32,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> -#include <sys/fcntl.h> #include <fcntl.h> #ifdef _MSC_VER # include <io.h> @@ -57,7 +56,10 @@ static DECLCALLBACK(void) rtRandAdvPosixGetBytes(PRTRANDINT pThis, uint8_t *pb, ssize_t cbRead = read(pThis->u.File.hFile, pb, cb); if ((size_t)cbRead != cb) { - ssize_t cTries = RT_MIN(cb, 256); + /* S10 has been observed returning 1040 bytes at the time from /dev/urandom. + Which means we need to do than 256 rounds to reach 668171 bytes if + that's what demanded by the caller (like tstRTMemWipe.cpp). */ + ssize_t cTries = RT_MAX(256, cb / 64); do { if (cbRead > 0) diff --git a/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp b/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp index 73f925c2..c72cd22f 100644 --- a/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp +++ b/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp @@ -146,20 +146,20 @@ static RTHEAPPAGE g_MemExecPosixHeap; #ifdef RT_OS_OS2 /* - * A quick mmap/munmap mockup for avoid duplicating lots of good code. + * A quick mmap/munmap mockup for avoid duplicating lots of good code. */ # define INCL_BASE # include <os2.h> -# undef MAP_PRIVATE +# undef MAP_PRIVATE # define MAP_PRIVATE 0 -# undef MAP_ANONYMOUS +# undef MAP_ANONYMOUS # define MAP_ANONYMOUS 0 # undef MAP_FAILED # define MAP_FAILED (void *)-1 # undef mmap -# define mmap iprt_mmap +# define mmap iprt_mmap # undef munmap -# define munmap iprt_munmap +# define munmap iprt_munmap static void *mmap(void *pvWhere, size_t cb, int fProt, int fFlags, int fd, off_t off) { @@ -605,12 +605,11 @@ int RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages) * Initializes the heap. * * @returns IPRT status code - * @param pvUser1 Unused. - * @param pvUser2 Unused. + * @param pvUser Unused. */ -static DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser) { - NOREF(pvUser1); NOREF(pvUser2); + NOREF(pvUser); int rc = RTHeapPageInit(&g_MemPagePosixHeap, false /*fExec*/); if (RT_SUCCESS(rc)) { @@ -663,7 +662,7 @@ static void *rtMemPagePosixAlloc(size_t cb, const char *pszTag, bool fZero, PRTH } else { - int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL, NULL); + int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL); if (RT_SUCCESS(rc)) rc = RTHeapPageAlloc(pHeap, cb >> PAGE_SHIFT, pszTag, fZero, &pv); if (RT_FAILURE(rc)) diff --git a/src/VBox/Runtime/r3/posix/sched-posix.cpp b/src/VBox/Runtime/r3/posix/sched-posix.cpp index 6fbf2f9f..4fa2bb9a 100644 --- a/src/VBox/Runtime/r3/posix/sched-posix.cpp +++ b/src/VBox/Runtime/r3/posix/sched-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/semevent-posix.cpp b/src/VBox/Runtime/r3/posix/semevent-posix.cpp index f2c40f3f..67d69cbb 100644 --- a/src/VBox/Runtime/r3/posix/semevent-posix.cpp +++ b/src/VBox/Runtime/r3/posix/semevent-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -48,7 +48,7 @@ # define pthread_yield() pthread_yield_np() #endif -#ifdef RT_OS_SOLARIS +#if defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU) # include <sched.h> # define pthread_yield() sched_yield() #endif @@ -397,7 +397,7 @@ DECL_FORCE_INLINE(int) rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillie * Get current time and calc end of wait time. */ struct timespec ts = {0,0}; -#ifdef RT_OS_DARWIN +#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU) struct timeval tv = {0,0}; gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec; diff --git a/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp b/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp index 8a1d066b..2875a9a0 100644 --- a/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp +++ b/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -481,7 +481,7 @@ static int rtSemEventMultiPosixWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis, struct timespec ts = {0,0}; if (!pThis->fMonotonicClock) { -#ifdef RT_OS_DARWIN +#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU) struct timeval tv = {0,0}; gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec; diff --git a/src/VBox/Runtime/r3/posix/semmutex-posix.cpp b/src/VBox/Runtime/r3/posix/semmutex-posix.cpp index e1e82558..89fa962c 100644 --- a/src/VBox/Runtime/r3/posix/semmutex-posix.cpp +++ b/src/VBox/Runtime/r3/posix/semmutex-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -65,6 +65,43 @@ struct RTSEMMUTEXINTERNAL #endif }; +#ifdef RT_OS_DARWIN +/** + * This function emulate pthread_mutex_timedlock on Mac OS X + */ +static int DarwinPthreadMutexTimedlock(pthread_mutex_t * mutex, const struct timespec * pTsAbsTimeout) +{ + int rc = 0; + struct timeval tv; + timespec ts = {0, 0}; + do + { + rc = pthread_mutex_trylock(mutex); + if (rc == EBUSY) + { + gettimeofday(&tv, NULL); + + ts.tv_sec = pTsAbsTimeout->tv_sec - tv.tv_sec; + ts.tv_nsec = pTsAbsTimeout->tv_nsec - tv.tv_sec; + + if (ts.tv_nsec < 0) + { + ts.tv_sec--; + ts.tv_nsec += 1000000000; + } + + if ( ts.tv_sec > 0 + && ts.tv_nsec > 0) + nanosleep(&ts, &ts); + } + else + break; + } while ( rc != 0 + || ts.tv_sec > 0); + return rc; +} +#endif + #undef RTSemMutexCreate RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem) @@ -241,15 +278,16 @@ DECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMil } else { -#ifdef RT_OS_DARWIN - AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API.")); - return VERR_NOT_IMPLEMENTED; -#else /* !RT_OS_DARWIN */ - /* - * Get current time and calc end of wait time. - */ struct timespec ts = {0,0}; +#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU) + + struct timeval tv = {0,0}; + gettimeofday(&tv, NULL); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; +#else clock_gettime(CLOCK_REALTIME, &ts); +#endif if (cMillies != 0) { ts.tv_nsec += (cMillies % 1000) * 1000000; @@ -262,14 +300,17 @@ DECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMil } /* take mutex */ +#ifndef RT_OS_DARWIN int rc = pthread_mutex_timedlock(&pThis->Mutex, &ts); +#else + int rc = DarwinPthreadMutexTimedlock(&pThis->Mutex, &ts); +#endif RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX); if (rc) { AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", hMutexSem, rc)); NOREF(rc); return RTErrConvertFromErrno(rc); } -#endif /* !RT_OS_DARWIN */ } /* diff --git a/src/VBox/Runtime/r3/posix/semrw-posix.cpp b/src/VBox/Runtime/r3/posix/semrw-posix.cpp index 81f71ef1..c6dfeb2f 100644 --- a/src/VBox/Runtime/r3/posix/semrw-posix.cpp +++ b/src/VBox/Runtime/r3/posix/semrw-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/symlink-posix.cpp b/src/VBox/Runtime/r3/posix/symlink-posix.cpp index f2c05da2..b3e10877 100644 --- a/src/VBox/Runtime/r3/posix/symlink-posix.cpp +++ b/src/VBox/Runtime/r3/posix/symlink-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/thread-posix.cpp b/src/VBox/Runtime/r3/posix/thread-posix.cpp index b212181a..66ccafb0 100644 --- a/src/VBox/Runtime/r3/posix/thread-posix.cpp +++ b/src/VBox/Runtime/r3/posix/thread-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -47,17 +47,22 @@ # include <mach/mach_init.h> # include <mach/mach_host.h> #endif -#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ || defined(RT_OS_LINUX) \ +#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ \ + || (defined(RT_OS_LINUX) && !defined(IN_RT_STATIC) /* static + dlsym = trouble */) \ || defined(IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP) # define IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP # include <dlfcn.h> #endif +#if defined(RT_OS_HAIKU) +# include <OS.h> +#endif #include <iprt/thread.h> #include <iprt/log.h> #include <iprt/assert.h> #include <iprt/asm.h> #include <iprt/err.h> +#include <iprt/initterm.h> #include <iprt/string.h> #include "internal/thread.h" @@ -115,20 +120,14 @@ static void rtThreadKeyDestruct(void *pvValue); static void rtThreadPosixPokeSignal(int iSignal); -DECLHIDDEN(int) rtThreadNativeInit(void) -{ - /* - * Allocate the TLS (key in posix terms) where we store the pointer to - * a threads RTTHREADINT structure. - */ - int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct); - if (rc) - return VERR_NO_TLS_FOR_SELF; - #ifdef RTTHREAD_POSIX_WITH_POKE +/** + * Try register the dummy signal handler for RTThreadPoke. + */ +static void rtThreadPosixSelectPokeSignal(void) +{ /* - * Try register the dummy signal handler for RTThreadPoke. - * Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads. + * Note! Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads. */ static const int s_aiSigCandidates[] = { @@ -144,34 +143,53 @@ DECLHIDDEN(int) rtThreadNativeInit(void) }; g_iSigPokeThread = -1; - for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++) + if (!RTR3InitIsUnobtrusive()) { - struct sigaction SigActOld; - if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld)) + for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++) { - if ( SigActOld.sa_handler == SIG_DFL - || SigActOld.sa_handler == rtThreadPosixPokeSignal) + struct sigaction SigActOld; + if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld)) { - struct sigaction SigAct; - RT_ZERO(SigAct); - SigAct.sa_handler = rtThreadPosixPokeSignal; - SigAct.sa_flags = 0; - sigfillset(&SigAct.sa_mask); - - /* ASSUMES no sigaction race... (lazy bird) */ - if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL)) + if ( SigActOld.sa_handler == SIG_DFL + || SigActOld.sa_handler == rtThreadPosixPokeSignal) { - g_iSigPokeThread = s_aiSigCandidates[iSig]; - break; + struct sigaction SigAct; + RT_ZERO(SigAct); + SigAct.sa_handler = rtThreadPosixPokeSignal; + SigAct.sa_flags = 0; + sigfillset(&SigAct.sa_mask); + + /* ASSUMES no sigaction race... (lazy bird) */ + if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL)) + { + g_iSigPokeThread = s_aiSigCandidates[iSig]; + break; + } + AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno)); } - AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno)); } + else + AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno)); } - else - AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno)); } +} #endif /* RTTHREAD_POSIX_WITH_POKE */ + +DECLHIDDEN(int) rtThreadNativeInit(void) +{ + /* + * Allocate the TLS (key in posix terms) where we store the pointer to + * a threads RTTHREADINT structure. + */ + int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct); + if (rc) + return VERR_NO_TLS_FOR_SELF; + +#ifdef RTTHREAD_POSIX_WITH_POKE + rtThreadPosixSelectPokeSignal(); +#endif + #ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP if (RT_SUCCESS(rc)) g_pfnThreadSetName = (PFNPTHREADSETNAME)(uintptr_t)dlsym(RTLD_DEFAULT, "pthread_setname_np"); @@ -179,6 +197,35 @@ DECLHIDDEN(int) rtThreadNativeInit(void) return rc; } +static void rtThreadPosixBlockSignals(void) +{ + /* + * Block SIGALRM - required for timer-posix.cpp. + * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling. + * It will not help much if someone creates threads directly using pthread_create. :/ + */ + if (!RTR3InitIsUnobtrusive()) + { + sigset_t SigSet; + sigemptyset(&SigSet); + sigaddset(&SigSet, SIGALRM); + sigprocmask(SIG_BLOCK, &SigSet, NULL); + } +#ifdef RTTHREAD_POSIX_WITH_POKE + if (g_iSigPokeThread != -1) + siginterrupt(g_iSigPokeThread, 1); +#endif +} + +DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void) +{ +#ifdef RTTHREAD_POSIX_WITH_POKE + Assert(!RTR3InitIsUnobtrusive()); + rtThreadPosixSelectPokeSignal(); +#endif + rtThreadPosixBlockSignals(); +} + /** * Destructor called when a thread terminates. @@ -221,19 +268,7 @@ static void rtThreadPosixPokeSignal(int iSignal) */ DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread) { - /* - * Block SIGALRM - required for timer-posix.cpp. - * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling. - * It will not help much if someone creates threads directly using pthread_create. :/ - */ - sigset_t SigSet; - sigemptyset(&SigSet); - sigaddset(&SigSet, SIGALRM); - sigprocmask(SIG_BLOCK, &SigSet, NULL); -#ifdef RTTHREAD_POSIX_WITH_POKE - if (g_iSigPokeThread != -1) - siginterrupt(g_iSigPokeThread, 1); -#endif + rtThreadPosixBlockSignals(); int rc = pthread_setspecific(g_SelfKey, pThread); if (!rc) @@ -266,19 +301,7 @@ static void *rtThreadNativeMain(void *pvArgs) ASMMemoryFence(); #endif - /* - * Block SIGALRM - required for timer-posix.cpp. - * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling. - * It will not help much if someone creates threads directly using pthread_create. :/ - */ - sigset_t SigSet; - sigemptyset(&SigSet); - sigaddset(&SigSet, SIGALRM); - sigprocmask(SIG_BLOCK, &SigSet, NULL); -#ifdef RTTHREAD_POSIX_WITH_POKE - if (g_iSigPokeThread != -1) - siginterrupt(g_iSigPokeThread, 1); -#endif + rtThreadPosixBlockSignals(); /* * Set the TLS entry and, if possible, the thread name. @@ -412,6 +435,15 @@ RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUs *pUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000; return VINF_SUCCESS; +#elif defined(RT_OS_HAIKU) + thread_info ThreadInfo; + status_t status = get_thread_info(find_thread(NULL), &ThreadInfo); + AssertReturn(status == B_OK, RTErrConvertFromErrno(status)); + + *pKernelTime = ThreadInfo.kernel_time / 1000; + *pUserTime = ThreadInfo.user_time / 1000; + + return VINF_SUCCESS; #else return VERR_NOT_IMPLEMENTED; #endif diff --git a/src/VBox/Runtime/r3/posix/thread2-posix.cpp b/src/VBox/Runtime/r3/posix/thread2-posix.cpp index b0402ed0..bd7e030e 100644 --- a/src/VBox/Runtime/r3/posix/thread2-posix.cpp +++ b/src/VBox/Runtime/r3/posix/thread2-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -62,7 +62,7 @@ RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies) pthread_yield_np(); #elif defined(RT_OS_FREEBSD) /* void pthread_yield */ pthread_yield(); -#elif defined(RT_OS_SOLARIS) +#elif defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU) sched_yield(); #else if (!pthread_yield()) @@ -101,7 +101,7 @@ RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies) pthread_yield_np(); #elif defined(RT_OS_FREEBSD) /* void pthread_yield */ pthread_yield(); -#elif defined(RT_OS_SOLARIS) +#elif defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU) sched_yield(); #else if (!pthread_yield()) @@ -130,7 +130,7 @@ RTDECL(bool) RTThreadYield(void) #endif #ifdef RT_OS_DARWIN pthread_yield_np(); -#elif defined(RT_OS_SOLARIS) +#elif defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU) sched_yield(); #else pthread_yield(); diff --git a/src/VBox/Runtime/r3/posix/time-posix.cpp b/src/VBox/Runtime/r3/posix/time-posix.cpp index bdb3dcb7..6f313afd 100644 --- a/src/VBox/Runtime/r3/posix/time-posix.cpp +++ b/src/VBox/Runtime/r3/posix/time-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/timelocal-posix.cpp b/src/VBox/Runtime/r3/posix/timelocal-posix.cpp index d65c0167..ce60f751 100644 --- a/src/VBox/Runtime/r3/posix/timelocal-posix.cpp +++ b/src/VBox/Runtime/r3/posix/timelocal-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/timer-posix.cpp b/src/VBox/Runtime/r3/posix/timer-posix.cpp index f6e75492..043709a1 100644 --- a/src/VBox/Runtime/r3/posix/timer-posix.cpp +++ b/src/VBox/Runtime/r3/posix/timer-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,6 +57,7 @@ #include <iprt/string.h> #include <iprt/once.h> #include <iprt/err.h> +#include <iprt/initterm.h> #include <iprt/critsect.h> #include "internal/magics.h" @@ -152,14 +153,12 @@ typedef struct RTTIMER * RTOnce callback that initializes the critical section. * * @returns RTCritSectInit return code. - * @param pvUser1 NULL, ignored. - * @param pvUser2 NULL, ignored. + * @param pvUser NULL, ignored. * */ -static DECLCALLBACK(int) rtTimerOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int) rtTimerOnce(void *pvUser) { - NOREF(pvUser1); - NOREF(pvUser2); + NOREF(pvUser); return RTCritSectInit(&g_TimerCritSect); } #endif @@ -406,6 +405,13 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_ if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) return VERR_NOT_SUPPORTED; + /* + * We need the signal masks to be set correctly, which they won't be in + * unobtrusive mode. + */ + if (RTR3InitIsUnobtrusive()) + return VERR_NOT_SUPPORTED; + #ifndef IPRT_WITH_POSIX_TIMERS /* * Check if timer is busy. @@ -539,7 +545,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_ /* * Do the global init first. */ - int rc = RTOnce(&g_TimerOnce, rtTimerOnce, NULL, NULL); + int rc = RTOnce(&g_TimerOnce, rtTimerOnce, NULL); if (RT_FAILURE(rc)) return rc; diff --git a/src/VBox/Runtime/r3/posix/tls-posix.cpp b/src/VBox/Runtime/r3/posix/tls-posix.cpp index c8005a59..c79e6e22 100644 --- a/src/VBox/Runtime/r3/posix/tls-posix.cpp +++ b/src/VBox/Runtime/r3/posix/tls-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/posix/utf8-posix.cpp b/src/VBox/Runtime/r3/posix/utf8-posix.cpp index 35ae6f3d..cb723eb7 100644 --- a/src/VBox/Runtime/r3/posix/utf8-posix.cpp +++ b/src/VBox/Runtime/r3/posix/utf8-posix.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -193,11 +193,13 @@ static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *p size_t cbOutLeft = cbOutput2; const void *pvInputLeft = pvInput; void *pvOutputLeft = pvOutput; -#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */ - if (iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1) + size_t cchNonRev; +#if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */ + cchNonRev = iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft); #else - if (iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1) + cchNonRev = iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft); #endif + if (cchNonRev != (size_t)-1) { if (!cbInLeft) { @@ -209,7 +211,9 @@ static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *p if (fUcs2Term) ((char *)pvOutputLeft)[1] = '\0'; *ppvOutput = pvOutput; - return VINF_SUCCESS; + if (cchNonRev == 0) + return VINF_SUCCESS; + return VWRN_NO_TRANSLATION; } errno = E2BIG; } @@ -319,11 +323,13 @@ static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char size_t cbOutLeft = cbOutput2; const void *pvInputLeft = pvInput; void *pvOutputLeft = pvOutput; -#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */ - if (iconv(icHandle, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1) + size_t cchNonRev; +#if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */ + cchNonRev = iconv(icHandle, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft); #else - if (iconv(icHandle, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1) + cchNonRev = iconv(icHandle, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft); #endif + if (cchNonRev != (size_t)-1) { if (!cbInLeft) { @@ -336,7 +342,9 @@ static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char if (fUcs2Term) ((char *)pvOutputLeft)[1] = '\0'; *ppvOutput = pvOutput; - return VINF_SUCCESS; + if (cchNonRev == 0) + return VINF_SUCCESS; + return VWRN_NO_TRANSLATION; } errno = E2BIG; } diff --git a/src/VBox/Runtime/r3/process.cpp b/src/VBox/Runtime/r3/process.cpp index 7be307f3..9f47814d 100644 --- a/src/VBox/Runtime/r3/process.cpp +++ b/src/VBox/Runtime/r3/process.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/socket.cpp b/src/VBox/Runtime/r3/socket.cpp index 42d42883..8678c37b 100644 --- a/src/VBox/Runtime/r3/socket.cpp +++ b/src/VBox/Runtime/r3/socket.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,6 +33,7 @@ # include <ws2tcpip.h> #else /* !RT_OS_WINDOWS */ # include <errno.h> +# include <sys/select.h> # include <sys/stat.h> # include <sys/socket.h> # include <netinet/in.h> @@ -110,6 +111,15 @@ /** How many pending connection. */ #define RTTCP_SERVER_BACKLOG 10 +/* Limit read and write sizes on Windows and OS/2. */ +#ifdef RT_OS_WINDOWS +# define RTSOCKET_MAX_WRITE (INT_MAX / 2) +# define RTSOCKET_MAX_READ (INT_MAX / 2) +#elif defined(RT_OS_OS2) +# define RTSOCKET_MAX_WRITE 0x10000 +# define RTSOCKET_MAX_READ 0x10000 +#endif + /******************************************************************************* * Structures and Typedefs * @@ -135,13 +145,15 @@ typedef struct RTSOCKETINT /** Indicates whether the socket is operating in blocking or non-blocking mode * currently. */ bool fBlocking; +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + /** The pollset currently polling this socket. This is NIL if no one is + * polling. */ + RTPOLLSET hPollSet; +#endif #ifdef RT_OS_WINDOWS /** The event semaphore we've associated with the socket handle. * This is WSA_INVALID_EVENT if not done. */ WSAEVENT hEvent; - /** The pollset currently polling this socket. This is NIL if no one is - * polling. */ - RTPOLLSET hPollSet; /** The events we're polling for. */ uint32_t fPollEvts; /** The events we're currently subscribing to with WSAEventSelect. @@ -397,9 +409,11 @@ int rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative) pThis->hNative = hNative; pThis->fClosed = false; pThis->fBlocking = true; +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + pThis->hPollSet = NIL_RTPOLLSET; +#endif #ifdef RT_OS_WINDOWS pThis->hEvent = WSA_INVALID_EVENT; - pThis->hPollSet = NIL_RTPOLLSET; pThis->fPollEvts = 0; pThis->fSubscribedEvts = 0; #endif @@ -853,8 +867,8 @@ RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size for (;;) { rtSocketErrorReset(); -#ifdef RT_OS_WINDOWS - int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead; +#ifdef RTSOCKET_MAX_READ + int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead; #else size_t cbNow = cbToRead; #endif @@ -920,8 +934,8 @@ RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t cbToRead = cbBuffer; rtSocketErrorReset(); RTSOCKADDRUNION u; -#ifdef RT_OS_WINDOWS - int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead; +#ifdef RTSOCKET_MAX_READ + int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead; int cbAddr = sizeof(u); #else size_t cbNow = cbToRead; @@ -967,8 +981,8 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe /* * Try write all at once. */ -#ifdef RT_OS_WINDOWS - int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer; +#ifdef RTSOCKET_MAX_WRITE + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; #else size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer; #endif @@ -994,8 +1008,8 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe pvBuffer = (char const *)pvBuffer + cbWritten; /* send */ -#ifdef RT_OS_WINDOWS - cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer; +#ifdef RTSOCKET_MAX_WRITE + cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; #else cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer; #endif @@ -1056,7 +1070,7 @@ RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuf * Must write all at once, otherwise it is a failure. */ #ifdef RT_OS_WINDOWS - int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer; + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; #else size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer; #endif @@ -1201,9 +1215,13 @@ RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, si return rc; rtSocketErrorReset(); -#ifdef RT_OS_WINDOWS - int cbNow = cbBuffer >= INT_MAX/2 ? INT_MAX/2 : (int)cbBuffer; +#ifdef RTSOCKET_MAX_READ + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; +#else + size_t cbNow = cbBuffer; +#endif +#ifdef RT_OS_WINDOWS int cbRead = recv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL); if (cbRead >= 0) { @@ -1216,7 +1234,7 @@ RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, si if (rc == VERR_TRY_AGAIN) rc = VINF_TRY_AGAIN; #else - ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL); + ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbNow, MSG_NOSIGNAL); if (cbRead >= 0) *pcbRead = cbRead; else if (errno == EAGAIN) @@ -1249,11 +1267,14 @@ RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuf return rc; rtSocketErrorReset(); -#ifdef RT_OS_WINDOWS - int cbNow = RT_MIN((int)cbBuffer, INT_MAX/2); +#ifdef RTSOCKET_MAX_WRITE + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; +#else + size_t cbNow = cbBuffer; +#endif +#ifdef RT_OS_WINDOWS int cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL); - if (cbWritten >= 0) { *pcbWritten = cbWritten; @@ -1752,7 +1773,6 @@ int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValu return rc; } -#ifdef RT_OS_WINDOWS /** * Internal RTPollSetAdd helper that returns the handle that should be added to @@ -1761,29 +1781,37 @@ int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValu * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure. * @param hSocket The socket handle. * @param fEvents The events we're polling for. - * @param ph where to put the primary handle. + * @param phNative Where to put the primary handle. */ -int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph) +int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PRTHCINTPTR phNative) { RTSOCKETINT *pThis = hSocket; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE); +#ifdef RT_OS_WINDOWS AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS); int rc = VINF_SUCCESS; if (pThis->hEvent != WSA_INVALID_EVENT) - *ph = pThis->hEvent; + *phNative = (RTHCINTPTR)pThis->hEvent; else { - *ph = pThis->hEvent = WSACreateEvent(); + pThis->hEvent = WSACreateEvent(); + *phNative = (RTHCINTPTR)pThis->hEvent; if (pThis->hEvent == WSA_INVALID_EVENT) rc = rtSocketError(); } rtSocketUnlock(pThis); return rc; + +#else /* !RT_OS_WINDOWS */ + *phNative = (RTHCUINTPTR)pThis->hNative; + return VINF_SUCCESS; +#endif /* !RT_OS_WINDOWS */ } +#ifdef RT_OS_WINDOWS /** * Undos the harm done by WSAEventSelect. @@ -1853,6 +1881,10 @@ static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents) return rc; } +#endif /* RT_OS_WINDOWS */ + + +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) /** * Checks for pending events. @@ -1863,12 +1895,13 @@ static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents) */ static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents) { - int rc = VINF_SUCCESS; - uint32_t fRetEvents = 0; + uint32_t fRetEvents = 0; LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents)); +# ifdef RT_OS_WINDOWS /* Make sure WSAEnumNetworkEvents returns what we want. */ + int rc = VINF_SUCCESS; if ((pThis->fSubscribedEvts & fEvents) != fEvents) rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents); @@ -1904,8 +1937,23 @@ static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents) /* Fall back on select if we hit an error above. */ if (RT_FAILURE(rc)) { - /** @todo */ + + } + +#else /* RT_OS_OS2 */ + int aFds[4] = { pThis->hNative, pThis->hNative, pThis->hNative, -1 }; + int rc = os2_select(aFds, 1, 1, 1, 0); + if (rc > 0) + { + if (aFds[0] == pThis->hNative) + fRetEvents |= RTPOLL_EVT_READ; + if (aFds[1] == pThis->hNative) + fRetEvents |= RTPOLL_EVT_WRITE; + if (aFds[2] == pThis->hNative) + fRetEvents |= RTPOLL_EVT_ERROR; + fRetEvents &= fEvents; } +#endif /* RT_OS_OS2 */ LogFlowFunc(("fRetEvents=%#x\n", fRetEvents)); return fRetEvents; @@ -1939,6 +1987,8 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent RTSOCKETINT *pThis = hSocket; AssertPtrReturn(pThis, UINT32_MAX); AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX); + /** @todo This isn't quite sane. Replace by critsect and open up concurrent + * reads and writes! */ if (rtSocketTryLock(pThis)) pThis->hPollSet = hPollSet; else @@ -1948,6 +1998,7 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent } /* (rtSocketPollCheck will reset the event object). */ +# ifdef RT_OS_WINDOWS uint32_t fRetEvents = pThis->fEventsSaved; pThis->fEventsSaved = 0; /* Reset */ fRetEvents |= rtSocketPollCheck(pThis, fEvents); @@ -1967,12 +2018,17 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent } } } +# else + uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents); +# endif if (fRetEvents || fNoWait) { if (pThis->cUsers == 1) { +# ifdef RT_OS_WINDOWS rtSocketPollClearEventAndRestoreBlocking(pThis); +# endif pThis->hPollSet = NIL_RTPOLLSET; } ASMAtomicDecU32(&pThis->cUsers); @@ -2008,6 +2064,7 @@ uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, /* Harvest events and clear the event mask for the next round of polling. */ uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents); +# ifdef RT_OS_WINDOWS pThis->fPollEvts = 0; /* @@ -2021,15 +2078,19 @@ uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, pThis->fEventsSaved = fRetEvents; fRetEvents = 0; } +# endif /* Make the socket blocking again and unlock the handle. */ if (pThis->cUsers == 1) { +# ifdef RT_OS_WINDOWS rtSocketPollClearEventAndRestoreBlocking(pThis); +# endif pThis->hPollSet = NIL_RTPOLLSET; } ASMAtomicDecU32(&pThis->cUsers); return fRetEvents; } -#endif /* RT_OS_WINDOWS */ +#endif /* RT_OS_WINDOWS || RT_OS_OS2 */ + diff --git a/src/VBox/Runtime/r3/solaris/Makefile.kup b/src/VBox/Runtime/r3/solaris/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/VBox/Runtime/r3/solaris/Makefile.kup diff --git a/src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp b/src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp new file mode 100644 index 00000000..44906788 --- /dev/null +++ b/src/VBox/Runtime/r3/solaris/RTSystemShutdown-solaris.cpp @@ -0,0 +1,102 @@ +/* $Id: RTSystemShutdown-solaris.cpp $ */ +/** @file + * IPRT - RTSystemShutdown, linux implementation. + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <iprt/system.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/env.h> +#include <iprt/err.h> +#include <iprt/process.h> +#include <iprt/string.h> + + +RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char *pszLogMsg) +{ + AssertPtrReturn(pszLogMsg, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTSYSTEM_SHUTDOWN_VALID_MASK), VERR_INVALID_PARAMETER); + + /* + * Assemble the argument vector. + */ + int iArg = 0; + const char *apszArgs[8]; + + RT_BZERO(apszArgs, sizeof(apszArgs)); + + apszArgs[iArg++] = "/usr/sbin/shutdown"; + apszArgs[iArg++] = "-y"; /* Pre-answer confirmation question. */ + apszArgs[iArg++] = "-i"; /* Change to the following state. */ + switch (fFlags & RTSYSTEM_SHUTDOWN_ACTION_MASK) + { + case RTSYSTEM_SHUTDOWN_HALT: + apszArgs[iArg++] = "0"; + break; + case RTSYSTEM_SHUTDOWN_REBOOT: + apszArgs[iArg++] = "6"; + break; + case RTSYSTEM_SHUTDOWN_POWER_OFF: + case RTSYSTEM_SHUTDOWN_POWER_OFF_HALT: + apszArgs[iArg++] = "5"; + break; + } + + apszArgs[iArg++] = "-g"; /* Grace period. */ + + char szWhen[80]; + if (cMsDelay < 500) + strcpy(szWhen, "0"); + else + RTStrPrintf(szWhen, sizeof(szWhen), "%u", (unsigned)((cMsDelay + 499) / 1000)); + apszArgs[iArg++] = szWhen; + + apszArgs[iArg++] = pszLogMsg; + + + /* + * Start the shutdown process and wait for it to complete. + */ + RTPROCESS hProc; + int rc = RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProc); + if (RT_FAILURE(rc)) + return rc; + + RTPROCSTATUS ProcStatus; + rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus); + if (RT_SUCCESS(rc)) + { + if ( ProcStatus.enmReason != RTPROCEXITREASON_NORMAL + || ProcStatus.iStatus != 0) + rc = VERR_SYS_SHUTDOWN_FAILED; + } + + return rc; +} + diff --git a/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp b/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp index 39726eda..66ef5286 100644 --- a/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp +++ b/src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010-2011 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -162,7 +162,7 @@ static int ReadFileNoIntr(int fd, void *pv, size_t cbToRead) * * @param fd Handle to the file to write to. * @param pv Pointer to what to write. - * @param cbToWrite Size of data to write. + * @param cbToWrite Size of data to write. * * @return IPRT status code. */ @@ -191,9 +191,9 @@ static int WriteFileNoIntr(int fd, const void *pv, size_t cbToWrite) * Read from a given offset in the process' address space. * * @param pSolProc Pointer to the solaris process. - * @param pv Where to read the data into. - * @param cb Size of the read buffer. - * @param off Offset to read from. + * @param off The offset to read from. + * @param pvBuf Where to read the data into. + * @param cbToRead Number of bytes to read. * * @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR. */ @@ -1263,51 +1263,8 @@ static int rtCoreDumperResumeThreads(PRTSOLCORE pSolCore) { AssertReturn(pSolCore, VERR_INVALID_POINTER); -#if 1 uint64_t cThreads; return rtCoreDumperForEachThread(pSolCore, &cThreads, resumeThread); -#else - PRTSOLCOREPROCESS pSolProc = &pSolCore->SolProc; - - char szCurThread[128]; - char szPath[PATH_MAX]; - PRTDIR pDir = NULL; - - RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pSolProc->Process); - RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pSolProc->hCurThread); - - int32_t cRunningThreads = 0; - int rc = RTDirOpen(&pDir, szPath); - if (RT_SUCCESS(rc)) - { - /* - * Loop through all our threads & resume them. - */ - RTDIRENTRY DirEntry; - while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL))) - { - if ( !strcmp(DirEntry.szName, ".") - || !strcmp(DirEntry.szName, "..")) - continue; - - if ( !strcmp(DirEntry.szName, szCurThread)) - continue; - - int32_t ThreadId = RTStrToInt32(DirEntry.szName); - _lwp_continue((lwpid_t)ThreadId); - ++cRunningThreads; - } - - CORELOG((CORELOG_NAME "ResumeAllThreads: resumed %d threads\n", cRunningThreads)); - RTDirClose(pDir); - } - else - { - CORELOGRELSYS((CORELOG_NAME "ResumeAllThreads: Failed to open %s\n", szPath)); - rc = VERR_READ_ERROR; - } - return rc; -#endif } @@ -2116,8 +2073,7 @@ static int rtCoreDumperDestroyCore(PRTSOLCORE pSolCore) /** - * Takes a core dump. This function has no other parameters than the context - * because it can be called from signal handlers. + * Takes a core dump. * * @param pContext The context of the caller. * @param pszOutputFile Path of the core file. If NULL is passed, the diff --git a/src/VBox/Runtime/r3/solaris/coredumper-solaris.h b/src/VBox/Runtime/r3/solaris/coredumper-solaris.h index 127fd9be..662effc6 100644 --- a/src/VBox/Runtime/r3/solaris/coredumper-solaris.h +++ b/src/VBox/Runtime/r3/solaris/coredumper-solaris.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010-2011 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp b/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp index 2b6d60b8..2f218305 100644 --- a/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp +++ b/src/VBox/Runtime/r3/solaris/fileaio-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -55,6 +55,8 @@ typedef struct RTFILEAIOCTXINTERNAL int iPort; /** Current number of requests active on this context. */ volatile int32_t cRequests; + /** Flags given during creation. */ + uint32_t fFlags; /** Magic value (RTFILEAIOCTX_MAGIC). */ uint32_t u32Magic; } RTFILEAIOCTXINTERNAL; @@ -270,11 +272,13 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered) return RTErrConvertFromErrno(rcSol); } -RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags) { int rc = VINF_SUCCESS; PRTFILEAIOCTXINTERNAL pCtxInt; AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL)); if (RT_UNLIKELY(!pCtxInt)) @@ -284,7 +288,8 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) pCtxInt->iPort = port_create(); if (RT_LIKELY(pCtxInt->iPort > 0)) { - pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; + pCtxInt->fFlags = fFlags; + pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; *phAioCtx = (RTFILEAIOCTX)pCtxInt; } else @@ -448,7 +453,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER); AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE); - if (RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0)) + if ( RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0) + && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS)) return VERR_FILE_AIO_NO_REQUEST; /* diff --git a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp index 0f2c6fdf..d21bbb42 100644 --- a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp +++ b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,19 +57,77 @@ static kstat_ctl_t *g_pKsCtl; static kstat_t **g_papCpuInfo; /** The number of entries in g_papCpuInfo */ static RTCPUID g_capCpuInfo; +/** Array of core ids. */ +static uint64_t *g_pu64CoreIds; +/** Number of entries in g_pu64CoreIds. */ +static size_t g_cu64CoreIds; +/** Number of cores in the system. */ +static size_t g_cCores; + + +/** + * Helper for getting the core ID for a given CPU/strand/hyperthread. + * + * @returns The core ID. + * @param idCpu The CPU ID instance. + */ +static inline uint64_t rtMpSolarisGetCoreId(RTCPUID idCpu) +{ + kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"core_id"); + Assert(pStat->data_type == KSTAT_DATA_LONG); + Assert(pStat->value.l >= 0); + AssertCompile(sizeof(uint64_t) >= sizeof(long)); /* Paranoia. */ + return (uint64_t)pStat->value.l; +} + + +/** + * Populates 'g_pu64CoreIds' array with unique core identifiers in the system. + * + * @returns VBox status code. + */ +static int rtMpSolarisGetCoreIds(void) +{ + for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++) + { + if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1) + { + /* Strands/Hyperthreads share the same core ID. */ + uint64_t u64CoreId = rtMpSolarisGetCoreId(idCpu); + bool fAddedCore = false; + for (RTCPUID i = 0; i < g_cCores; i++) + { + if (g_pu64CoreIds[i] == u64CoreId) + { + fAddedCore = true; + break; + } + } + + if (!fAddedCore) + { + g_pu64CoreIds[g_cCores] = u64CoreId; + ++g_cCores; + } + } + else + return VERR_INTERNAL_ERROR_2; + } + + return VINF_SUCCESS; +} /** * Run once function that initializes the kstats we need here. * * @returns IPRT status code. - * @param pvUser1 Unused. - * @param pvUser2 Unused. + * @param pvUser Unused. */ -static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser) { int rc = VINF_SUCCESS; - NOREF(pvUser1); NOREF(pvUser2); + NOREF(pvUser); /* * Open kstat and find the cpu_info entries for each of the CPUs. @@ -81,25 +139,40 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) g_papCpuInfo = (kstat_t **)RTMemAllocZ(g_capCpuInfo * sizeof(kstat_t *)); if (g_papCpuInfo) { - rc = RTCritSectInit(&g_MpSolarisCritSect); - if (RT_SUCCESS(rc)) + g_cu64CoreIds = g_capCpuInfo; + g_pu64CoreIds = (uint64_t *)RTMemAllocZ(g_cu64CoreIds * sizeof(uint64_t)); + if (g_pu64CoreIds) { - RTCPUID i = 0; - for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next) + rc = RTCritSectInit(&g_MpSolarisCritSect); + if (RT_SUCCESS(rc)) { - if (!strcmp(pKsp->ks_module, "cpu_info")) + RTCPUID i = 0; + for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next) { - AssertBreak(i < g_capCpuInfo); - g_papCpuInfo[i++] = pKsp; - /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */ + if (!RTStrCmp(pKsp->ks_module, "cpu_info")) + { + AssertBreak(i < g_capCpuInfo); + g_papCpuInfo[i++] = pKsp; + /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */ + } } + + rc = rtMpSolarisGetCoreIds(); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + Log(("rtMpSolarisGetCoreIds failed. rc=%Rrc\n", rc)); } - return VINF_SUCCESS; + RTMemFree(g_pu64CoreIds); + g_pu64CoreIds = NULL; } + else + rc = VERR_NO_MEMORY; /* bail out, we failed. */ RTMemFree(g_papCpuInfo); + g_papCpuInfo = NULL; } else rc = VERR_NO_MEMORY; @@ -119,6 +192,21 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) /** + * RTOnceEx() cleanup function. + * + * @param pvUser Unused. + * @param fLazyCleanUpOk Whether lazy cleanup is okay or not. + */ +static DECLCALLBACK(void) rtMpSolarisCleanUp(void *pvUser, bool fLazyCleanUpOk) +{ + if (g_pKsCtl) + kstat_close(g_pKsCtl); + RTMemFree(g_pu64CoreIds); + RTMemFree(g_papCpuInfo); +} + + +/** * Worker for RTMpGetCurFrequency and RTMpGetMaxFrequency. * * @returns The desired frequency on success, 0 on failure. @@ -126,10 +214,10 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) * @param idCpu The CPU ID. * @param pszStatName The cpu_info stat name. */ -static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName) +static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, const char *pszStatName) { uint64_t u64 = 0; - int rc = RTOnce(&g_MpSolarisOnce, rtMpSolarisOnce, NULL, NULL); + int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */); if (RT_SUCCESS(rc)) { if ( idCpu < g_capCpuInfo @@ -141,7 +229,8 @@ static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName) { if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1) { - kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], pszStatName); + /* Solaris really need to fix their APIs. Explicitly cast for now. */ + kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char*)pszStatName); if (pStat) { Assert(pStat->data_type == KSTAT_DATA_UINT64 || pStat->data_type == KSTAT_DATA_LONG); @@ -280,7 +369,7 @@ RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet) { #ifdef RT_STRICT - long cCpusPresent = 0; + RTCPUID cCpusPresent = 0; #endif RTCpuSetEmpty(pSet); RTCPUID cCpus = RTMpGetCount(); @@ -305,3 +394,60 @@ RTDECL(RTCPUID) RTMpGetPresentCount(void) return sysconf(_SC_NPROCESSORS_CONF); } + +RTDECL(RTCPUID) RTMpGetPresentCoreCount(void) +{ + return RTMpGetCoreCount(); +} + + +RTDECL(RTCPUID) RTMpGetCoreCount(void) +{ + int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */); + if (RT_SUCCESS(rc)) + return g_cCores; + + return 0; +} + + +RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void) +{ + RTCPUID uOnlineCores = 0; + int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */); + if (RT_SUCCESS(rc)) + { + rc = RTCritSectEnter(&g_MpSolarisCritSect); + AssertRC(rc); + + /* + * For each core in the system, count how many are currently online. + */ + for (RTCPUID j = 0; j < g_cCores; j++) + { + uint64_t u64CoreId = g_pu64CoreIds[j]; + for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++) + { + rc = kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0); + AssertReturn(rc != -1, 0 /* rc */); + uint64_t u64ThreadCoreId = rtMpSolarisGetCoreId(idCpu); + if (u64ThreadCoreId == u64CoreId) + { + kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"state"); + Assert(pStat->data_type == KSTAT_DATA_CHAR); + if( !RTStrNCmp(pStat->value.c, PS_ONLINE, sizeof(PS_ONLINE) - 1) + || !RTStrNCmp(pStat->value.c, PS_NOINTR, sizeof(PS_NOINTR) - 1)) + { + uOnlineCores++; + break; /* Move to the next core. We have at least 1 hyperthread online in the current core. */ + } + } + } + } + + RTCritSectLeave(&g_MpSolarisCritSect); + } + + return uOnlineCores; +} + diff --git a/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp b/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp index 40baf8c2..ffaad258 100644 --- a/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp +++ b/src/VBox/Runtime/r3/solaris/rtProcInitExePath-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp b/src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp new file mode 100644 index 00000000..e5efe631 --- /dev/null +++ b/src/VBox/Runtime/r3/solaris/systemmem-solaris.cpp @@ -0,0 +1,172 @@ +/* $Id: systemmem-solaris.cpp $ */ +/** @file + * IPRT - RTSystemQueryTotalRam, Solaris ring-3. + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <iprt/system.h> +#include "internal/iprt.h" + +#include <iprt/err.h> +#include <iprt/assert.h> +#include <iprt/critsect.h> +#include <iprt/once.h> +#include <iprt/param.h> + +#include <errno.h> +#include <kstat.h> + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Initialize globals once. */ +static RTONCE g_rtSysMemSolInitOnce = RTONCE_INITIALIZER; +/** Critical section serializing access to g_pKStatCtl and the other handles. */ +static RTCRITSECT g_rtSysMemSolCritSect; +/** The kstate control handle. */ +static kstat_ctl_t *g_pKStatCtl = NULL; +/** The unix.system_pages handle. */ +static kstat_t *g_pUnixSysPages = NULL; +/** The zfs.archstats handle. */ +static kstat_t *g_pZfsArcStats = NULL; + + +/** @callback_method_impl{FNRTONCE} */ +static DECLCALLBACK(int) rtSysMemSolInit(void *pvUser) +{ + int rc = RTCritSectInit(&g_rtSysMemSolCritSect); + if (RT_SUCCESS(rc)) + { + g_pKStatCtl = kstat_open(); + if (g_pKStatCtl) + { + g_pUnixSysPages = kstat_lookup(g_pKStatCtl, (char *)"unix", 0, (char *)"system_pages"); + if (g_pUnixSysPages) + { + g_pZfsArcStats = kstat_lookup(g_pKStatCtl, (char *)"zfs", 0, (char *)"arcstats"); /* allow NULL */ + return VINF_SUCCESS; + } + + rc = RTErrConvertFromErrno(errno); + kstat_close(g_pKStatCtl); + g_pKStatCtl = NULL; + } + else + rc = RTErrConvertFromErrno(errno); + } + return rc; +} + + +/** @callback_method_impl{FNRTONCECLEANUP} */ +static DECLCALLBACK(void) rtSysMemSolCleanUp(void *pvUser, bool fLazyCleanUpOk) +{ + RTCritSectDelete(&g_rtSysMemSolCritSect); + + kstat_close(g_pKStatCtl); + g_pKStatCtl = NULL; + g_pUnixSysPages = NULL; + g_pZfsArcStats = NULL; + + NOREF(pvUser); NOREF(fLazyCleanUpOk); +} + + + +RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb) +{ + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + + int rc = RTOnceEx(&g_rtSysMemSolInitOnce, rtSysMemSolInit, rtSysMemSolCleanUp, NULL); + if (RT_SUCCESS(rc)) + { + rc = RTCritSectEnter(&g_rtSysMemSolCritSect); + if (RT_SUCCESS(rc)) + { + if (kstat_read(g_pKStatCtl, g_pUnixSysPages, NULL) != -1) + { + kstat_named_t *pData = (kstat_named_t *)kstat_data_lookup(g_pUnixSysPages, (char *)"physmem"); + if (pData) + *pcb = (uint64_t)pData->value.ul * PAGE_SIZE; + else + rc = RTErrConvertFromErrno(errno); + } + else + rc = RTErrConvertFromErrno(errno); + RTCritSectLeave(&g_rtSysMemSolCritSect); + } + } + return rc; +} + + +RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb) +{ + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + + int rc = RTOnceEx(&g_rtSysMemSolInitOnce, rtSysMemSolInit, rtSysMemSolCleanUp, NULL); + if (RT_SUCCESS(rc)) + { + rc = RTCritSectEnter(&g_rtSysMemSolCritSect); + if (RT_SUCCESS(rc)) + { + if (kstat_read(g_pKStatCtl, g_pUnixSysPages, NULL) != -1) + { + kstat_named_t *pData = (kstat_named_t *)kstat_data_lookup(g_pUnixSysPages, (char *)"freemem"); + if (pData) + { + *pcb = (uint64_t)pData->value.ul * PAGE_SIZE; + + /* + * Adjust for ZFS greedyness if possible. + * (c_min is the target minimum size of the cache, it is not + * an absolute minimum.) + */ + if ( g_pZfsArcStats + && kstat_read(g_pKStatCtl, g_pZfsArcStats, NULL) != -1) + { + kstat_named_t *pCurSize = (kstat_named_t *)kstat_data_lookup(g_pZfsArcStats, (char *)"size"); + kstat_named_t *pMinSize = (kstat_named_t *)kstat_data_lookup(g_pZfsArcStats, (char *)"c_min"); + if ( pCurSize + && pMinSize + && pCurSize->value.ul > pMinSize->value.ul) + { + *pcb += pCurSize->value.ul - pMinSize->value.ul; + } + } + } + else + rc = RTErrConvertFromErrno(errno); + } + + RTCritSectLeave(&g_rtSysMemSolCritSect); + } + } + return rc; +} + diff --git a/src/VBox/Runtime/r3/stream.cpp b/src/VBox/Runtime/r3/stream.cpp index e220e5c7..d8b90ccb 100644 --- a/src/VBox/Runtime/r3/stream.cpp +++ b/src/VBox/Runtime/r3/stream.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -311,6 +311,7 @@ RTR3DECL(int) RTStrmOpen(const char *pszFilename, const char *pszMode, PRTSTREAM pStream->i32Error = VINF_SUCCESS; pStream->fCurrentCodeSet = false; pStream->fBinary = fBinary; + pStream->fRecheckMode = false; #ifndef HAVE_FWRITE_UNLOCKED pStream->pCritSect = NULL; #endif /* HAVE_FWRITE_UNLOCKED */ diff --git a/src/VBox/Runtime/r3/tcp.cpp b/src/VBox/Runtime/r3/tcp.cpp index 151dee86..7c6b2ef4 100644 --- a/src/VBox/Runtime/r3/tcp.cpp +++ b/src/VBox/Runtime/r3/tcp.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -805,11 +805,19 @@ RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer) RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock) { + return RTTcpClientConnectEx(pszAddress, uPort, pSock, NULL); +} + + +RTR3DECL(int) RTTcpClientConnectEx(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock, + PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie) +{ /* * Validate input. */ AssertReturn(uPort > 0, VERR_INVALID_PARAMETER); AssertPtrReturn(pszAddress, VERR_INVALID_POINTER); + AssertPtrNullReturn(ppCancelCookie, VERR_INVALID_POINTER); /* * Resolve the address. @@ -828,7 +836,25 @@ RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCK { RTSocketSetInheritance(Sock, false /*fInheritable*/); - rc = rtSocketConnect(Sock, &Addr); + if (!ppCancelCookie) + rc = rtSocketConnect(Sock, &Addr); + else + { + RTSocketRetain(Sock); + if (ASMAtomicCmpXchgPtr(ppCancelCookie, (PRTTCPCLIENTCONNECTCANCEL)Sock, NULL)) + { + rc = rtSocketConnect(Sock, &Addr); + if (ASMAtomicCmpXchgPtr(ppCancelCookie, NULL, (PRTTCPCLIENTCONNECTCANCEL)Sock)) + RTSocketRelease(Sock); + else + rc = VERR_CANCELLED; + } + else + { + RTSocketRelease(Sock); + rc = VERR_CANCELLED; + } + } if (RT_SUCCESS(rc)) { *pSock = Sock; @@ -837,10 +863,28 @@ RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCK rtTcpClose(Sock, "RTTcpClientConnect", false /*fTryGracefulShutdown*/); } + if (ppCancelCookie) + *ppCancelCookie = NULL; return rc; } +RTR3DECL(int) RTTcpClientCancelConnect(PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie) +{ + AssertPtrReturn(ppCancelCookie, VERR_INVALID_POINTER); + + AssertCompile(NIL_RTSOCKET == NULL); + RTSOCKET hSock = (RTSOCKET)ASMAtomicXchgPtr((void * volatile *)ppCancelCookie, (void *)(uintptr_t)0xdead9999); + if (hSock != NIL_RTSOCKET) + { + int rc = rtTcpClose(hSock, "RTTcpClientCancelConnect", false /*fTryGracefulShutdown*/); + AssertRCReturn(rc, rc); + } + + return VINF_SUCCESS; +} + + RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock) { return rtTcpClose(Sock, "RTTcpClientClose", true /*fTryGracefulShutdown*/); diff --git a/src/VBox/Runtime/r3/test.cpp b/src/VBox/Runtime/r3/test.cpp index 6c9abcc3..5688dc6c 100644 --- a/src/VBox/Runtime/r3/test.cpp +++ b/src/VBox/Runtime/r3/test.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -91,6 +91,8 @@ typedef struct RTTESTINT uint32_t cbGuard; /** The verbosity level. */ RTTESTLVL enmMaxLevel; + /** The creation flags. */ + uint32_t fFlags; /** Critical section serializing output. */ @@ -111,6 +113,8 @@ typedef struct RTTESTINT const char *pszSubTest; /** The length of the sub-test name. */ size_t cchSubTest; + /** Whether the current subtest should figure as 'SKIPPED'. */ + bool fSubTestSkipped; /** Whether we've reported the sub-test result or not. */ bool fSubTestReported; /** The start error count of the current subtest. */ @@ -123,6 +127,10 @@ typedef struct RTTESTINT /** Set if XML output is enabled. */ bool fXmlEnabled; + /** Set if we omit the top level test in the XML report. */ + bool fXmlOmitTopTest; + /** Set if we've reported the top test (for RTTEST_C_XML_DELAY_TOP_TEST). */ + bool fXmlTopTestDone; enum { kXmlPos_ValueStart, kXmlPos_Value, @@ -185,8 +193,6 @@ static void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *psz static void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...); static void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va); static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...); -static void rtTestXmlElemValueV(PRTTESTINT pTest, const char *pszFormat, va_list va); -static void rtTestXmlElemValue(PRTTESTINT pTest, const char *pszFormat, ...); static void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag); static void rtTestXmlEnd(PRTTESTINT pTest); @@ -205,31 +211,28 @@ static RTTLS g_iTestTls = NIL_RTTLS; * Init TLS index once. * * @returns IPRT status code. - * @param pvUser1 Ignored. - * @param pvUser2 Ignored. + * @param pvUser Ignored. */ -static DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser) { - NOREF(pvUser1); - NOREF(pvUser2); + NOREF(pvUser); return RTTlsAllocEx(&g_iTestTls, NULL); } - -/** - * Creates a test instance. - * - * @returns IPRT status code. - * @param pszTest The test name. - * @param phTest Where to store the test instance handle. - */ -RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest) +RTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel, + RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest) { + AssertReturn(!(fFlags & ~RTTEST_C_VALID_MASK), VERR_INVALID_PARAMETER); + AssertPtrNull(phTest); + AssertPtrNull(pszXmlFile); + /* RTTESTLVL_INVALID is valid! */ + AssertReturn(enmMaxLevel >= RTTESTLVL_INVALID && enmMaxLevel < RTTESTLVL_END, VERR_INVALID_PARAMETER); + /* * Global init. */ - int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL, NULL); + int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL); if (RT_FAILURE(rc)) return rc; @@ -243,7 +246,8 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest) pTest->pszTest = RTStrDup(pszTest); pTest->cchTest = strlen(pszTest); pTest->cbGuard = PAGE_SIZE * 7; - pTest->enmMaxLevel = RTTESTLVL_SUB_TEST; + pTest->enmMaxLevel = enmMaxLevel == RTTESTLVL_INVALID ? RTTESTLVL_INFO : enmMaxLevel; + pTest->fFlags = fFlags; pTest->pOutStrm = g_pStdOut; pTest->fNewLine = true; @@ -252,12 +256,14 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest) pTest->pszSubTest = NULL; pTest->cchSubTest = 0; + pTest->fSubTestSkipped = false; pTest->fSubTestReported = true; pTest->cSubTestAtErrors = 0; pTest->cSubTests = 0; pTest->cSubTestsFailed = 0; pTest->fXmlEnabled = false; + pTest->fXmlTopTestDone = false; pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd; pTest->hXmlPipe = NIL_RTPIPE; pTest->hXmlFile = NIL_RTFILE; @@ -273,82 +279,109 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest) * Associate it with our TLS entry unless there is already * an instance there. */ - if (!RTTlsGet(g_iTestTls)) + if ( !(fFlags & RTTEST_C_NO_TLS) + && !RTTlsGet(g_iTestTls)) rc = RTTlsSet(g_iTestTls, pTest); if (RT_SUCCESS(rc)) { /* - * Pick up overrides from the environment. + * Output level override? */ char szEnvVal[RTPATH_MAX]; - rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szEnvVal, sizeof(szEnvVal), NULL); - if (RT_SUCCESS(rc)) + if ((fFlags & RTTEST_C_USE_ENV) && enmMaxLevel == RTTESTLVL_INVALID) { - char *pszMaxLevel = RTStrStrip(szEnvVal); - if (!strcmp(pszMaxLevel, "all")) - pTest->enmMaxLevel = RTTESTLVL_DEBUG; - if (!strcmp(pszMaxLevel, "quiet")) - pTest->enmMaxLevel = RTTESTLVL_FAILURE; - else if (!strcmp(pszMaxLevel, "debug")) - pTest->enmMaxLevel = RTTESTLVL_DEBUG; - else if (!strcmp(pszMaxLevel, "info")) - pTest->enmMaxLevel = RTTESTLVL_INFO; - else if (!strcmp(pszMaxLevel, "sub_test")) - pTest->enmMaxLevel = RTTESTLVL_SUB_TEST; - else if (!strcmp(pszMaxLevel, "failure")) - pTest->enmMaxLevel = RTTESTLVL_FAILURE; + rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szEnvVal, sizeof(szEnvVal), NULL); + if (RT_SUCCESS(rc)) + { + char *pszMaxLevel = RTStrStrip(szEnvVal); + if (!strcmp(pszMaxLevel, "all")) + pTest->enmMaxLevel = RTTESTLVL_DEBUG; + if (!strcmp(pszMaxLevel, "quiet")) + pTest->enmMaxLevel = RTTESTLVL_FAILURE; + else if (!strcmp(pszMaxLevel, "debug")) + pTest->enmMaxLevel = RTTESTLVL_DEBUG; + else if (!strcmp(pszMaxLevel, "info")) + pTest->enmMaxLevel = RTTESTLVL_INFO; + else if (!strcmp(pszMaxLevel, "sub_test")) + pTest->enmMaxLevel = RTTESTLVL_SUB_TEST; + else if (!strcmp(pszMaxLevel, "failure")) + pTest->enmMaxLevel = RTTESTLVL_FAILURE; + } + else if (rc != VERR_ENV_VAR_NOT_FOUND) + RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc); } /* * Any test driver we are connected or should connect to? */ - rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_PIPE", szEnvVal, sizeof(szEnvVal), NULL); - if (RT_SUCCESS(rc)) + if ((fFlags & RTTEST_C_USE_ENV) && iNativeTestPipe == -1) { - RTHCINTPTR hNative = -1; + rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_PIPE", szEnvVal, sizeof(szEnvVal), NULL); + if (RT_SUCCESS(rc)) + { #if ARCH_BITS == 64 - rc = RTStrToInt64Full(szEnvVal, 0, &hNative); + rc = RTStrToInt64Full(szEnvVal, 0, &iNativeTestPipe); #else - rc = RTStrToInt32Full(szEnvVal, 0, &hNative); + rc = RTStrToInt32Full(szEnvVal, 0, &iNativeTestPipe); #endif - if (RT_SUCCESS(rc)) - { - rc = RTPipeFromNative(&pTest->hXmlPipe, hNative, RTPIPE_N_WRITE); - if (RT_SUCCESS(rc)) - pTest->fXmlEnabled = true; - else + if (RT_FAILURE(rc)) { - RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTPipeFromNative(,\"%s\",WRITE) -> %Rrc\n", pszTest, szEnvVal, rc); - pTest->hXmlPipe = NIL_RTPIPE; + RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTStrToInt32Full(\"%s\") -> %Rrc\n", + pszTest, szEnvVal, rc); + iNativeTestPipe = -1; } } + else if (rc != VERR_ENV_VAR_NOT_FOUND) + RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_PIPE) -> %Rrc\n", pszTest, rc); + } + if (iNativeTestPipe != -1) + { + rc = RTPipeFromNative(&pTest->hXmlPipe, iNativeTestPipe, RTPIPE_N_WRITE); + if (RT_SUCCESS(rc)) + pTest->fXmlEnabled = true; else - RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTStrToInt32Full(\"%s\") -> %Rrc\n", pszTest, szEnvVal, rc); + { + RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTPipeFromNative(,%p,WRITE) -> %Rrc\n", + pszTest, iNativeTestPipe, rc); + pTest->hXmlPipe = NIL_RTPIPE; + } } - else if (rc != VERR_ENV_VAR_NOT_FOUND) - RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_PIPE) -> %Rrc\n", pszTest, rc); /* * Any test file we should write the test report to? */ - rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_FILE", szEnvVal, sizeof(szEnvVal), NULL); - if (RT_SUCCESS(rc)) + if ((fFlags & RTTEST_C_USE_ENV) && pszXmlFile == NULL) { - rc = RTFileOpen(&pTest->hXmlFile, szEnvVal, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE); + rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_FILE", szEnvVal, sizeof(szEnvVal), NULL); + if (RT_SUCCESS(rc)) + pszXmlFile = szEnvVal; + else if (rc != VERR_ENV_VAR_NOT_FOUND) + RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc); + } + if (pszXmlFile && *pszXmlFile) + { + rc = RTFileOpen(&pTest->hXmlFile, pszXmlFile, + RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE); if (RT_SUCCESS(rc)) pTest->fXmlEnabled = true; else { - RTStrmPrintf(g_pStdErr, "%s: test file error: RTFileOpen(,\"%s\",) -> %Rrc\n", pszTest, szEnvVal, rc); + RTStrmPrintf(g_pStdErr, "%s: test file error: RTFileOpen(,\"%s\",) -> %Rrc\n", pszTest, pszXmlFile, rc); pTest->hXmlFile = NIL_RTFILE; } } else if (rc != VERR_ENV_VAR_NOT_FOUND) RTStrmPrintf(g_pStdErr, "%s: test file error: RTEnvGetEx(IPRT_TEST_FILE) -> %Rrc\n", pszTest, rc); + /* + * What do we report in the XML stream/file.? + */ + pTest->fXmlOmitTopTest = (fFlags & RTTEST_C_XML_OMIT_TOP_TEST) + || ( (fFlags & RTTEST_C_USE_ENV) + && RTEnvExistEx(RTENV_DEFAULT, "IPRT_TEST_OMIT_TOP_TEST")); /* - * Tell the test driver that we're up. + * Tell the test driver that we're up to. */ rtTestXmlStart(pTest, pszTest); @@ -368,6 +401,12 @@ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest) } +RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest) +{ + return RTTestCreateEx(pszTest, RTTEST_C_USE_ENV, RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, NULL /*pszXmlFile*/, phTest); +} + + RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest) { int rc = RTR3InitExeNoArguments(0); @@ -376,6 +415,30 @@ RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest) RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExeNoArguments failed with rc=%Rrc\n", pszTest, rc); return RTEXITCODE_INIT; } + + rc = RTTestCreate(pszTest, phTest); + if (RT_FAILURE(rc)) + { + RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc); + return RTEXITCODE_INIT; + } + return RTEXITCODE_SUCCESS; +} + + +RTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***papszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest) +{ + int rc; + if (cArgs <= 0 && papszArgs == NULL) + rc = RTR3InitExeNoArguments(fRtInit); + else + rc = RTR3InitExe(cArgs, papszArgs, fRtInit); + if (RT_FAILURE(rc)) + { + RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExe(,,%#x) failed with rc=%Rrc\n", pszTest, fRtInit, rc); + return RTEXITCODE_INIT; + } + rc = RTTestCreate(pszTest, phTest); if (RT_FAILURE(rc)) { @@ -454,6 +517,34 @@ RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest) } +RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName) +{ + PRTTESTINT pTest = hTest; + RTTEST_GET_VALID_RETURN(pTest); + AssertPtrReturn(pszName, VERR_INVALID_POINTER); + AssertReturn(*pszName, VERR_INVALID_PARAMETER); + + size_t cchName = strlen(pszName); + AssertReturn(cchName < 128, VERR_INVALID_PARAMETER); + char *pszDupName = RTStrDup(pszName); + if (!pszDupName) + return VERR_NO_STR_MEMORY; + + RTCritSectEnter(&pTest->Lock); + RTCritSectEnter(&pTest->OutputLock); + + char *pszOldName = (char *)pTest->pszTest; + pTest->pszTest = pszDupName; + pTest->cchTest = cchName; + + RTCritSectLeave(&pTest->OutputLock); + RTCritSectLeave(&pTest->Lock); + + RTStrFree(pszOldName); + return VINF_SUCCESS; +} + + /** * Allocate a block of guarded memory. * @@ -683,7 +774,9 @@ static void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest) { rtTestXmlOutput(pTest, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd; - rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest); + pTest->fXmlTopTestDone = !(pTest->fFlags & RTTEST_C_XML_DELAY_TOP_TEST) || pTest->fXmlOmitTopTest; + if (pTest->fXmlTopTestDone && !pTest->fXmlOmitTopTest) + rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest); } } @@ -795,43 +888,6 @@ static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char /** - * Writes an element value, or a part of one, taking care of all the escaping. - * - * The caller must own the instance lock. - * - * @param pTest The test instance. - * @param pszFormat The value format string. - * @param va The format arguments. - */ -static void rtTestXmlElemValueV(PRTTESTINT pTest, const char *pszFormat, va_list va) -{ - if (pTest->fXmlEnabled) - { - char *pszValue; - RTStrAPrintfV(&pszValue, pszFormat, va); - if (pszValue) - { - rtTestXmlOutput(pTest, "%RMes", pszValue); - RTStrFree(pszValue); - } - pTest->eXmlState = RTTESTINT::kXmlPos_Value; - } -} - - -/** - * Wrapper around rtTestXmlElemValueV. - */ -static void rtTestXmlElemValue(PRTTESTINT pTest, const char *pszFormat, ...) -{ - va_list va; - va_start(va, pszFormat); - rtTestXmlElemValueV(pTest, pszFormat, va); - va_end(va); -} - - -/** * Ends the current element. * * The caller must own the instance lock. @@ -879,7 +935,7 @@ static void rtTestXmlEnd(PRTTESTINT pTest) * final timestamp and some certainty that the XML is valid. */ size_t i = pTest->cXmlElements; - AssertReturnVoid(i > 0); + AssertReturnVoid(i > 0 || pTest->fXmlOmitTopTest || !pTest->fXmlTopTestDone); while (i-- > 1) { const char *pszTag = pTest->apszXmlElements[pTest->cXmlElements]; @@ -891,9 +947,13 @@ static void rtTestXmlEnd(PRTTESTINT pTest) rtTestXmlOutput(pTest, "</%s>\n", pszTag); pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd; } - rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"", - pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors); - rtTestXmlOutput(pTest, "</Test>\n"); + + if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone) + { + rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"", + pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors); + rtTestXmlOutput(pTest, "</Test>\n"); + } /* * Close the XML outputs. @@ -1130,15 +1190,24 @@ static int rtTestSubTestReport(PRTTESTINT pTest) uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors; if (!cErrors) { - rtTestXmlElem(pTest, "Passed", NULL); - rtTestXmlElemEnd(pTest, "SubTest"); - cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest); + if (!pTest->fSubTestSkipped) + { + rtTestXmlElem(pTest, "Passed", NULL); + rtTestXmlElemEnd(pTest, "Test"); + cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest); + } + else + { + rtTestXmlElem(pTest, "Skipped", NULL); + rtTestXmlElemEnd(pTest, "Test"); + cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: SKIPPED\n", pTest->pszSubTest); + } } else { pTest->cSubTestsFailed++; rtTestXmlElem(pTest, "Failed", "errors=\"%u\"", cErrors); - rtTestXmlElemEnd(pTest, "SubTest"); + rtTestXmlElemEnd(pTest, "Test"); cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: FAILED (%u errors)\n", pTest->pszSubTest, cErrors); } @@ -1267,13 +1336,20 @@ RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest) pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors); pTest->pszSubTest = RTStrDup(pszSubTest); pTest->cchSubTest = strlen(pszSubTest); + pTest->fSubTestSkipped = false; pTest->fSubTestReported = false; int cch = 0; if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG) cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest); - rtTestXmlElemStart(pTest, "SubTest", "name=%RMas", pszSubTest); + if (!pTest->fXmlTopTestDone) + { + pTest->fXmlTopTestDone = true; + rtTestXmlElemStart(pTest, "Test", "name=%RMas", pTest->pszTest); + } + + rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszSubTest); RTCritSectLeave(&pTest->Lock); @@ -1337,7 +1413,7 @@ RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va) RTR3DECL(int) RTTestSubDone(RTTEST hTest) { PRTTESTINT pTest = hTest; - RTTEST_GET_VALID_RETURN_RC(pTest, -1); + RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE); RTCritSectEnter(&pTest->Lock); int cch = rtTestSubCleanup(pTest); @@ -1361,7 +1437,8 @@ RTR3DECL(int) RTTestSubDone(RTTEST hTest) RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va) { PRTTESTINT pTest = hTest; - RTTEST_GET_VALID_RETURN_RC(pTest, -1); + AssertPtr(pszFormat); + RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE); int cch = 0; if (pTest->enmMaxLevel >= RTTESTLVL_INFO) @@ -1404,6 +1481,44 @@ RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...) } +RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va) +{ + PRTTESTINT pTest = hTest; + AssertPtrNull(pszFormat); + RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE); + + pTest->fSubTestSkipped = true; + + int cch = 0; + if (pszFormat && *pszFormat && pTest->enmMaxLevel >= RTTESTLVL_INFO) + { + va_list va2; + va_copy(va2, va); + + RTCritSectEnter(&pTest->OutputLock); + cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2); + RTCritSectLeave(&pTest->OutputLock); + + va_end(va2); + } + + return cch; +} + + +RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...) +{ + va_list va; + + va_start(va, pszFormat); + int cch = RTTestSkippedV(hTest, pszFormat, va); + va_end(va); + + return cch; +} + + + /** * Gets the unit name. * @@ -1438,6 +1553,13 @@ static const char *rtTestUnitName(RTTESTUNIT enmUnit) case RTTESTUNIT_NS_PER_OCCURRENCE: return "ns/occurrences"; case RTTESTUNIT_NS_PER_PACKET: return "ns/packet"; case RTTESTUNIT_NS_PER_ROUND_TRIP: return "ns/roundtrips"; + case RTTESTUNIT_INSTRS: return "ins"; + case RTTESTUNIT_INSTRS_PER_SEC: return "ins/sec"; + case RTTESTUNIT_NONE: return ""; + case RTTESTUNIT_PP1K: return "pp1k"; + case RTTESTUNIT_PP10K: return "pp10k"; + case RTTESTUNIT_PPM: return "ppm"; + case RTTESTUNIT_PPB: return "ppb"; /* No default so gcc helps us keep this up to date. */ case RTTESTUNIT_INVALID: @@ -1457,9 +1579,7 @@ RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, const char *pszUnit = rtTestUnitName(enmUnit); RTCritSectEnter(&pTest->Lock); - rtTestXmlElemStart(pTest, "Value", "name=%RMas unit=%RMas", pszName, pszUnit); - rtTestXmlElemValue(pTest, "%llu", u64Value); - rtTestXmlElemEnd(pTest, "Value"); + rtTestXmlElem(pTest, "Value", "name=%RMas unit=%RMas value=\"%llu\"", pszName, pszUnit, u64Value); RTCritSectLeave(&pTest->Lock); RTCritSectEnter(&pTest->OutputLock); @@ -1510,6 +1630,7 @@ RTR3DECL(int) RTTestErrorInc(RTTEST hTest) } + /** * Get the current error count. * @@ -1526,6 +1647,15 @@ RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest) } +RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest) +{ + PRTTESTINT pTest = hTest; + RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX); + + return ASMAtomicReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors; +} + + /** * Increments the error counter and prints a failure message. * @@ -1538,7 +1668,7 @@ RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest) RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va) { PRTTESTINT pTest = hTest; - RTTEST_GET_VALID_RETURN_RC(pTest, -1); + RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE); RTTestErrorInc(pTest); diff --git a/src/VBox/Runtime/r3/testi.cpp b/src/VBox/Runtime/r3/testi.cpp index e143e3c1..b0c78828 100644 --- a/src/VBox/Runtime/r3/testi.cpp +++ b/src/VBox/Runtime/r3/testi.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/udp.cpp b/src/VBox/Runtime/r3/udp.cpp index a5a2cc22..5e46b959 100644 --- a/src/VBox/Runtime/r3/udp.cpp +++ b/src/VBox/Runtime/r3/udp.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp b/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp index 683d6ee4..8c3d86b5 100644 --- a/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp +++ b/src/VBox/Runtime/r3/win/RTHandleGetStandard-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp b/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp index 2f3c16c0..69d028a0 100644 --- a/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp +++ b/src/VBox/Runtime/r3/win/RTLogWriteDebugger-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp b/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp index 57831910..8621a36b 100644 --- a/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp +++ b/src/VBox/Runtime/r3/win/RTSystemQueryDmiString-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -165,8 +165,11 @@ RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t c /* * Before we do anything with COM, we have to initialize it. */ + bool fUninit = true; HRESULT hrc = rtSystemDmiWinInitialize(); - if (FAILED(hrc)) + if (hrc == RPC_E_CHANGED_MODE) + fUninit = false; /* don't fail if already initialized */ + else if (FAILED(hrc)) return VERR_NOT_SUPPORTED; int rc = VERR_NOT_SUPPORTED; @@ -246,7 +249,8 @@ RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t c } else hrc = E_OUTOFMEMORY; - rtSystemDmiWinTerminate(); + if (fUninit) + rtSystemDmiWinTerminate(); if (FAILED(hrc) && rc == VERR_NOT_SUPPORTED) rc = VERR_NOT_SUPPORTED; return rc; diff --git a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp index 50dee1aa..28c34625 100644 --- a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp +++ b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -27,9 +27,11 @@ /******************************************************************************* * Header Files * *******************************************************************************/ +#include "internal/iprt.h" #include <Windows.h> #include <WinUser.h> +#include "internal-r3-win.h" #include <iprt/system.h> #include <iprt/assert.h> #include <iprt/string.h> @@ -39,35 +41,6 @@ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ -/** - * Windows OS type as determined by rtSystemWinOSType(). - */ -typedef enum RTWINOSTYPE -{ - kRTWinOSType_UNKNOWN = 0, - kRTWinOSType_9XFIRST = 1, - kRTWinOSType_95 = kRTWinOSType_9XFIRST, - kRTWinOSType_95SP1, - kRTWinOSType_95OSR2, - kRTWinOSType_98, - kRTWinOSType_98SP1, - kRTWinOSType_98SE, - kRTWinOSType_ME, - kRTWinOSType_9XLAST = 99, - kRTWinOSType_NTFIRST = 100, - kRTWinOSType_NT31 = kRTWinOSType_NTFIRST, - kRTWinOSType_NT351, - kRTWinOSType_NT4, - kRTWinOSType_2K, - kRTWinOSType_XP, - kRTWinOSType_2003, - kRTWinOSType_VISTA, - kRTWinOSType_2008, - kRTWinOSType_7, - kRTWinOSType_8, - kRTWinOSType_NT_UNKNOWN = 199, - kRTWinOSType_NT_LAST = kRTWinOSType_UNKNOWN -} RTWINOSTYPE; /** * These are the PRODUCT_* defines found in the Vista Platform SDK and returned @@ -111,112 +84,6 @@ typedef enum RTWINPRODTYPE /** - * Translates OSVERSIONINOFEX into a Windows OS type. - * - * @returns The Windows OS type. - * @param pOSInfoEx The OS info returned by Windows. - * - * @remarks This table has been assembled from Usenet postings, personal - * observations, and reading other people's code. Please feel - * free to add to it or correct it. - * <pre> - dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber -95 1 4 0 950 -95 SP1 1 4 0 >950 && <=1080 -95 OSR2 1 4 <10 >1080 -98 1 4 10 1998 -98 SP1 1 4 10 >1998 && <2183 -98 SE 1 4 10 >=2183 -ME 1 4 90 3000 - -NT 3.51 2 3 51 1057 -NT 4 2 4 0 1381 -2000 2 5 0 2195 -XP 2 5 1 2600 -2003 2 5 2 3790 -Vista 2 6 0 - -CE 1.0 3 1 0 -CE 2.0 3 2 0 -CE 2.1 3 2 1 -CE 3.0 3 3 0 -</pre> - */ -static RTWINOSTYPE rtSystemWinOSType(OSVERSIONINFOEX const *pOSInfoEx) -{ - RTWINOSTYPE enmVer = kRTWinOSType_UNKNOWN; - BYTE const bProductType = pOSInfoEx->wProductType; - DWORD const dwPlatformId = pOSInfoEx->dwPlatformId; - DWORD const dwMinorVersion = pOSInfoEx->dwMinorVersion; - DWORD const dwMajorVersion = pOSInfoEx->dwMajorVersion; - DWORD const dwBuildNumber = pOSInfoEx->dwBuildNumber & 0xFFFF; /* Win 9x needs this. */ - - if ( dwPlatformId == VER_PLATFORM_WIN32_WINDOWS - && dwMajorVersion == 4) - { - if ( dwMinorVersion < 10 - && dwBuildNumber == 950) - enmVer = kRTWinOSType_95; - else if ( dwMinorVersion < 10 - && dwBuildNumber > 950 - && dwBuildNumber <= 1080) - enmVer = kRTWinOSType_95SP1; - else if ( dwMinorVersion < 10 - && dwBuildNumber > 1080) - enmVer = kRTWinOSType_95OSR2; - else if ( dwMinorVersion == 10 - && dwBuildNumber == 1998) - enmVer = kRTWinOSType_98; - else if ( dwMinorVersion == 10 - && dwBuildNumber > 1998 - && dwBuildNumber < 2183) - enmVer = kRTWinOSType_98SP1; - else if ( dwMinorVersion == 10 - && dwBuildNumber >= 2183) - enmVer = kRTWinOSType_98SE; - else if (dwMinorVersion == 90) - enmVer = kRTWinOSType_ME; - } - else if (dwPlatformId == VER_PLATFORM_WIN32_NT) - { - if ( dwMajorVersion == 3 - && dwMinorVersion == 51) - enmVer = kRTWinOSType_NT351; - else if ( dwMajorVersion == 4 - && dwMinorVersion == 0) - enmVer = kRTWinOSType_NT4; - else if ( dwMajorVersion == 5 - && dwMinorVersion == 0) - enmVer = kRTWinOSType_2K; - else if ( dwMajorVersion == 5 - && dwMinorVersion == 1) - enmVer = kRTWinOSType_XP; - else if ( dwMajorVersion == 5 - && dwMinorVersion == 2) - enmVer = kRTWinOSType_2003; - else if ( dwMajorVersion == 6 - && dwMinorVersion == 0) - { - if (bProductType != VER_NT_WORKSTATION) - enmVer = kRTWinOSType_2008; - else - enmVer = kRTWinOSType_VISTA; - } - else if ( dwMajorVersion == 6 - && dwMinorVersion == 1) - enmVer = kRTWinOSType_7; - else if ( dwMajorVersion == 6 - && dwMinorVersion == 2) - enmVer = kRTWinOSType_8; - else - enmVer = kRTWinOSType_NT_UNKNOWN; - } - - return enmVer; -} - - -/** * Wrapper around the GetProductInfo API. * * @returns The vista type. @@ -224,7 +91,7 @@ static RTWINOSTYPE rtSystemWinOSType(OSVERSIONINFOEX const *pOSInfoEx) static RTWINPRODTYPE rtSystemWinGetProductInfo(DWORD dwOSMajorVersion, DWORD dwOSMinorVersion, DWORD dwSpMajorVersion, DWORD dwSpMinorVersion) { BOOL (WINAPI *pfnGetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD); - pfnGetProductInfo = (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "GetProductInfo"); + pfnGetProductInfo = (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProductInfo"); if (pfnGetProductInfo) { DWORD dwProductType = kRTWinProdType_UNDEFINED; @@ -291,48 +158,21 @@ static void rtSystemWinAppendProductType(char *pszTmp) */ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo) { - int rc; - /* * Make sure it's terminated correctly in case of error. */ *pszInfo = '\0'; /* - * Query the Windows version. - * - * ASSUMES OSVERSIONINFOEX starts with the exact same layout as OSVERSIONINFO (safe). + * Check that we got the windows version at init time. */ - OSVERSIONINFOEX OSInfoEx; - memset(&OSInfoEx, '\0', sizeof(OSInfoEx)); - OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (!GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)) - { - DWORD err = GetLastError(); - rc = RTErrConvertFromWin32(err); - AssertMsgFailedReturn(("err=%d\n", err), rc == VERR_BUFFER_OVERFLOW ? VERR_INTERNAL_ERROR : rc); - } - - /* Get extended version info for 2000 and later. */ - if ( OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT - && OSInfoEx.dwMajorVersion >= 5) - { - ZeroMemory(&OSInfoEx, sizeof(OSInfoEx)); - OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (!GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)) - { - DWORD err = GetLastError(); - rc = RTErrConvertFromWin32(err); - AssertMsgFailedReturn(("err=%d\n", err), rc == VERR_BUFFER_OVERFLOW ? VERR_INTERNAL_ERROR : rc); - } - } + AssertReturn(g_WinOsInfoEx.dwOSVersionInfoSize, VERR_WRONG_ORDER); /* * Service the request. */ char szTmp[512]; szTmp[0] = '\0'; - rc = VINF_SUCCESS; switch (enmInfo) { /* @@ -340,8 +180,7 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t */ case RTSYSOSINFO_PRODUCT: { - RTWINOSTYPE enmVer = rtSystemWinOSType(&OSInfoEx); - switch (enmVer) + switch (g_enmWinVer) { case kRTWinOSType_95: strcpy(szTmp, "Windows 95"); break; case kRTWinOSType_95SP1: strcpy(szTmp, "Windows 95 (Service Pack 1)"); break; @@ -355,10 +194,10 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t case kRTWinOSType_2K: strcpy(szTmp, "Windows 2000"); break; case kRTWinOSType_XP: strcpy(szTmp, "Windows XP"); - if (OSInfoEx.wSuiteMask & VER_SUITE_PERSONAL) + if (g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL) strcat(szTmp, " Home"); - if ( OSInfoEx.wProductType == VER_NT_WORKSTATION - && !(OSInfoEx.wSuiteMask & VER_SUITE_PERSONAL)) + if ( g_WinOsInfoEx.wProductType == VER_NT_WORKSTATION + && !(g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL)) strcat(szTmp, " Professional"); #if 0 /** @todo fixme */ if (GetSystemMetrics(SM_MEDIACENTER)) @@ -376,15 +215,18 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t case kRTWinOSType_2008: strcpy(szTmp, "Windows 2008"); break; case kRTWinOSType_7: strcpy(szTmp, "Windows 7"); break; case kRTWinOSType_8: strcpy(szTmp, "Windows 8"); break; + case kRTWinOSType_81: strcpy(szTmp, "Windows 8.1"); break; case kRTWinOSType_NT_UNKNOWN: - RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u", OSInfoEx.dwMajorVersion, OSInfoEx.dwMinorVersion); + RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u", + g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion); break; default: AssertFailed(); case kRTWinOSType_UNKNOWN: - RTStrPrintf(szTmp, sizeof(szTmp), "Unknown %d v%u.%u", OSInfoEx.dwPlatformId, OSInfoEx.dwMajorVersion, OSInfoEx.dwMinorVersion); + RTStrPrintf(szTmp, sizeof(szTmp), "Unknown %d v%u.%u", + g_WinOsInfoEx.dwPlatformId, g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion); break; } break; @@ -395,8 +237,8 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t */ case RTSYSOSINFO_RELEASE: { - RTWINOSTYPE enmVer = rtSystemWinOSType(&OSInfoEx); - RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", OSInfoEx.dwMajorVersion, OSInfoEx.dwMinorVersion, OSInfoEx.dwBuildNumber); + RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", + g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion, g_WinOsInfoEx.dwBuildNumber); break; } @@ -406,24 +248,25 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t */ case RTSYSOSINFO_SERVICE_PACK: { - if (OSInfoEx.wServicePackMajor) + if (g_WinOsInfoEx.wServicePackMajor) { - if (OSInfoEx.wServicePackMinor) - RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u", (unsigned)OSInfoEx.wServicePackMajor, (unsigned)OSInfoEx.wServicePackMinor); + if (g_WinOsInfoEx.wServicePackMinor) + RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u", + (unsigned)g_WinOsInfoEx.wServicePackMajor, (unsigned)g_WinOsInfoEx.wServicePackMinor); else - RTStrPrintf(szTmp, sizeof(szTmp), "%u", (unsigned)OSInfoEx.wServicePackMajor); + RTStrPrintf(szTmp, sizeof(szTmp), "%u", + (unsigned)g_WinOsInfoEx.wServicePackMajor); } - else if (OSInfoEx.szCSDVersion[0]) + else if (g_WinOsInfoEx.szCSDVersion[0]) { /* just copy the entire string. */ - memcpy(szTmp, OSInfoEx.szCSDVersion, sizeof(OSInfoEx.szCSDVersion)); - szTmp[sizeof(OSInfoEx.szCSDVersion)] = '\0'; - AssertCompile(sizeof(szTmp) > sizeof(OSInfoEx.szCSDVersion)); + memcpy(szTmp, g_WinOsInfoEx.szCSDVersion, sizeof(g_WinOsInfoEx.szCSDVersion)); + szTmp[sizeof(g_WinOsInfoEx.szCSDVersion)] = '\0'; + AssertCompile(sizeof(szTmp) > sizeof(g_WinOsInfoEx.szCSDVersion)); } else { - RTWINOSTYPE enmVer = rtSystemWinOSType(&OSInfoEx); - switch (enmVer) + switch (g_enmWinVer) { case kRTWinOSType_95SP1: strcpy(szTmp, "1"); break; case kRTWinOSType_98SP1: strcpy(szTmp, "1"); break; @@ -444,15 +287,13 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t size_t cchTmp = strlen(szTmp); Assert(cchTmp < sizeof(szTmp)); if (cchTmp < cchInfo) - memcpy(pszInfo, szTmp, cchTmp + 1); - else { - memcpy(pszInfo, szTmp, cchInfo - 1); - pszInfo[cchInfo - 1] = '\0'; - if (RT_SUCCESS(rc)) - rc = VERR_BUFFER_OVERFLOW; + memcpy(pszInfo, szTmp, cchTmp + 1); + return VINF_SUCCESS; } - return VINF_SUCCESS; + memcpy(pszInfo, szTmp, cchInfo - 1); + pszInfo[cchInfo - 1] = '\0'; + return VERR_BUFFER_OVERFLOW; } @@ -481,7 +322,8 @@ RTDECL(int) RTSystemQueryOSInfo(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchIn case RTSYSOSINFO_VERSION: default: *pszInfo = '\0'; - return VERR_NOT_SUPPORTED; } + + return VERR_NOT_SUPPORTED; } diff --git a/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp b/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp index 62a25bc3..2ddb96c8 100644 --- a/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp +++ b/src/VBox/Runtime/r3/win/RTSystemShutdown-win.cpp @@ -53,9 +53,9 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char BOOL fForceAppsClosed = fFlags & RTSYSTEM_SHUTDOWN_FORCE ? TRUE : FALSE; /* - * Do the + * Do the */ - if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/, + if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/, pwszLogMsg, cSecsTimeout, fForceAppsClosed, @@ -70,7 +70,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char if (dwErr == ERROR_ACCESS_DENIED) { HANDLE hToken = NULL; - if (OpenThreadToken(GetCurrentThread(), + if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE /*OpenAsSelf*/, &hToken)) @@ -80,7 +80,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char dwErr = GetLastError(); if (dwErr == ERROR_NO_TOKEN) { - if (OpenProcessToken(GetCurrentProcess(), + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) dwErr = NO_ERROR; @@ -91,7 +91,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char if (dwErr == NO_ERROR) { - union + union { TOKEN_PRIVILEGES TokenPriv; char ab[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)]; @@ -107,7 +107,7 @@ RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char NULL, NULL) ) { - if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/, + if (InitiateSystemShutdownW(NULL /*pwszMachineName = NULL = localhost*/, pwszLogMsg, cSecsTimeout, fForceAppsClosed, diff --git a/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp b/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp index 8083f98d..7792b794 100644 --- a/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp +++ b/src/VBox/Runtime/r3/win/RTUuidCreate-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def b/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def index fc314a4d..e1ac857f 100644 --- a/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def +++ b/src/VBox/Runtime/r3/win/VBoxRT-openssl-ose.def @@ -32,8 +32,8 @@ ; ; OpenSSL symbols ; - _CONF_get_section - _CONF_get_string +;; _CONF_get_section +;; _CONF_get_string a2d_ASN1_OBJECT a2i_ASN1_INTEGER a2i_ASN1_STRING @@ -442,10 +442,10 @@ CRYPTO_dbg_free CRYPTO_dbg_get_options CRYPTO_dbg_malloc - CRYPTO_dbg_pop_info - CRYPTO_dbg_push_info +;; CRYPTO_dbg_pop_info +;; CRYPTO_dbg_push_info CRYPTO_dbg_realloc - CRYPTO_dbg_remove_all_info +;; CRYPTO_dbg_remove_all_info CRYPTO_dbg_set_options CRYPTO_destroy_dynlockid CRYPTO_dup_ex_data @@ -474,7 +474,7 @@ CRYPTO_is_mem_check_on CRYPTO_lock CRYPTO_malloc - CRYPTO_malloc_debug_init +;; CRYPTO_malloc_debug_init CRYPTO_malloc_locked CRYPTO_mem_ctrl CRYPTO_mem_leaks @@ -502,7 +502,7 @@ CRYPTO_set_mem_debug_options CRYPTO_set_mem_ex_functions CRYPTO_set_mem_functions - CRYPTO_set_mem_info_functions +;; CRYPTO_set_mem_info_functions CRYPTO_strdup CRYPTO_thread_id d2i_ACCESS_DESCRIPTION @@ -1123,8 +1123,8 @@ NOTICEREF_new o2i_ECPublicKey OBJ_add_object - OBJ_bsearch - OBJ_bsearch_ex +;; OBJ_bsearch +;; OBJ_bsearch_ex OBJ_cleanup OBJ_cmp OBJ_create @@ -1283,7 +1283,7 @@ RSA_size RSA_up_ref RSA_verify - RSAPrivateKey_asn1_meth +;; RSAPrivateKey_asn1_meth RSAPrivateKey_dup RSAPublicKey_dup s2i_ASN1_INTEGER @@ -1428,7 +1428,7 @@ X509_ALGOR_set0 X509_alias_get0 X509_alias_set1 - X509_asn1_meth +;; X509_asn1_meth X509_ATTRIBUTE_count X509_ATTRIBUTE_create X509_ATTRIBUTE_create_by_NID diff --git a/src/VBox/Runtime/r3/win/VBoxRT-openssl.def b/src/VBox/Runtime/r3/win/VBoxRT-openssl.def index 01e269b5..f872e71c 100644 --- a/src/VBox/Runtime/r3/win/VBoxRT-openssl.def +++ b/src/VBox/Runtime/r3/win/VBoxRT-openssl.def @@ -9,7 +9,7 @@ ; ; -; Copyright (C) 2009-2012 Oracle Corporation +; Copyright (C) 2009-2013 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; @@ -476,11 +476,6 @@ c2i_ASN1_OBJECT CERTIFICATEPOLICIES_free CERTIFICATEPOLICIES_new - COMP_compress_block - COMP_CTX_free - COMP_CTX_new - COMP_expand_block - COMP_zlib CONF_dump_bio CONF_dump_fp CONF_free @@ -961,7 +956,6 @@ ERR_get_state ERR_get_string_table ERR_lib_error_string - ERR_load_ERR_strings ERR_load_strings ERR_peek_error ERR_peek_error_line @@ -1690,7 +1684,6 @@ SSLeay SSLeay_version string_to_hex - stub_VBOX_BIO_printf SXNET_add_id_asc SXNET_add_id_INTEGER SXNET_add_id_ulong @@ -2234,7 +2227,8 @@ ssl_cert_inst ssl_cert_new ssl_cert_type - ssl_check_clienthello_tlsext + ssl_check_clienthello_tlsext_early + ssl_check_clienthello_tlsext_late SSL_check_private_key ssl_check_serverhello_tlsext SSL_CIPHER_description diff --git a/src/VBox/Runtime/r3/win/VBoxRT-win32.def b/src/VBox/Runtime/r3/win/VBoxRT-win32.def index 8764142a..e36769fd 100644 --- a/src/VBox/Runtime/r3/win/VBoxRT-win32.def +++ b/src/VBox/Runtime/r3/win/VBoxRT-win32.def @@ -4,7 +4,7 @@ ; ; -; Copyright (C) 2006-2007 Oracle Corporation +; Copyright (C) 2006-2012 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/VBoxRT-win64.def b/src/VBox/Runtime/r3/win/VBoxRT-win64.def index 4a1eb1de..434c7be3 100644 --- a/src/VBox/Runtime/r3/win/VBoxRT-win64.def +++ b/src/VBox/Runtime/r3/win/VBoxRT-win64.def @@ -4,7 +4,7 @@ ; ; -; Copyright (C) 2006-2007 Oracle Corporation +; Copyright (C) 2006-2012 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/alloc-win.cpp b/src/VBox/Runtime/r3/win/alloc-win.cpp index 7e052673..25879154 100644 --- a/src/VBox/Runtime/r3/win/alloc-win.cpp +++ b/src/VBox/Runtime/r3/win/alloc-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/allocex-win.cpp b/src/VBox/Runtime/r3/win/allocex-win.cpp new file mode 100644 index 00000000..30de9aa7 --- /dev/null +++ b/src/VBox/Runtime/r3/win/allocex-win.cpp @@ -0,0 +1,120 @@ +/* $Id: allocex-win.cpp $ */ +/** @file + * IPRT - Memory Allocation, Extended Alloc Workers, Windows. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define RTMEM_NO_WRAP_TO_EF_APIS +#include <iprt/mem.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/param.h> +#include "../allocex.h" + +#include <Windows.h> + + +static int rtMemAllocExInRange(size_t cbAlloc, uint32_t fFlags, void **ppv, uintptr_t uAddr, uintptr_t uAddrLast) +{ + /* + * Try with every possible address hint since the possible range is very limited. + */ + DWORD fPageProt = (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); + while (uAddr <= uAddrLast) + { + MEMORY_BASIC_INFORMATION MemInfo; + SIZE_T cbRange = VirtualQuery((void *)uAddr, &MemInfo, sizeof(MemInfo)); + AssertReturn(cbRange == sizeof(MemInfo), VERR_NOT_SUPPORTED); + Assert(MemInfo.RegionSize > 0); + + if ( MemInfo.State == MEM_FREE + && MemInfo.RegionSize >= cbAlloc) + { + void *pv = VirtualAlloc((void *)uAddr, cbAlloc, MEM_RESERVE | MEM_COMMIT, fPageProt); + if ((uintptr_t)pv == uAddr) + { + *ppv = pv; + return VINF_SUCCESS; + } + AssertStmt(!pv, VirtualFree(pv, cbAlloc, MEM_RELEASE)); + } + + /* skip ahead */ + uintptr_t uAddrNext = (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize; + if (uAddrNext <= uAddr) + break; + uAddr += uAddrNext; + } + + return VERR_NO_MEMORY; +} + + +DECLHIDDEN(int) rtMemAllocEx16BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) +{ + cbAlloc = RT_ALIGN_Z(cbAlloc, PAGE_SIZE); + AssertReturn(cbAlloc <= _64K - PAGE_SIZE, VERR_NO_MEMORY); + + /* Seems this doesn't work on W7/64... */ + return rtMemAllocExInRange(cbAlloc, fFlags, ppv, PAGE_SIZE, _64K - cbAlloc); +} + + +DECLHIDDEN(int) rtMemAllocEx32BitReach(size_t cbAlloc, uint32_t fFlags, void **ppv) +{ + cbAlloc = RT_ALIGN_Z(cbAlloc, PAGE_SIZE); + AssertReturn(cbAlloc <= _2G+_1G, VERR_NO_MEMORY); + + /* + * Just try first. + */ + DWORD fPageProt = (fFlags & RTMEMALLOCEX_FLAGS_EXEC ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); + void *pv = VirtualAlloc(NULL, cbAlloc, MEM_RESERVE | MEM_COMMIT, fPageProt); + if (!pv) + return VERR_NO_MEMORY; + if ((uintptr_t)pv + cbAlloc - 1 < _4G) + { + *ppv = pv; + return VINF_SUCCESS; + } + VirtualFree(pv, cbAlloc, MEM_RELEASE); + + /* + * No luck, do address scan based allocation. + */ + return rtMemAllocExInRange(cbAlloc, fFlags, ppv, _64K, _4G - cbAlloc); +} + + +DECLHIDDEN(void) rtMemFreeExYyBitReach(void *pv, size_t cb, uint32_t fFlags) +{ + BOOL fRc = VirtualFree(pv, cb, MEM_RELEASE); + Assert(fRc); +} + diff --git a/src/VBox/Runtime/r3/win/dir-win.cpp b/src/VBox/Runtime/r3/win/dir-win.cpp index 2494b8b4..5c57315f 100644 --- a/src/VBox/Runtime/r3/win/dir-win.cpp +++ b/src/VBox/Runtime/r3/win/dir-win.cpp @@ -1,10 +1,10 @@ /* $Id: dir-win.cpp $ */ /** @file - * IPRT - Directory, win32. + * IPRT - Directory, Windows. */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,20 +30,17 @@ *******************************************************************************/ #define LOG_GROUP RTLOGGROUP_DIR #include <Windows.h> -#include <io.h> #include <iprt/dir.h> #include <iprt/path.h> -#include <iprt/alloc.h> +#include <iprt/mem.h> #include <iprt/string.h> #include <iprt/assert.h> -#include <iprt/param.h> #include <iprt/err.h> #include <iprt/file.h> #include <iprt/log.h> #include "internal/fs.h" #include "internal/path.h" -#include "internal/dir.h" @@ -129,339 +126,6 @@ RTDECL(int) RTDirFlush(const char *pszPath) } -int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) -{ - /* - * Setup the search expression. - * - * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal() - * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow - * it when adding the wildcard expression. - */ - size_t cchExpr; - const char *pszExpr; - if (pDir->enmFilter == RTDIRFILTER_WINNT) - { - pszExpr = pDir->pszFilter; - cchExpr = pDir->cchFilter + 1; - } - else - { - pszExpr = "*"; - cchExpr = sizeof("*"); - } - if (pDir->cchPath + cchExpr > RTPATH_MAX) - return VERR_FILENAME_TOO_LONG; - memcpy(pszPathBuf + pDir->cchPath, pszExpr, cchExpr); - - - /* - * Attempt opening the search. - */ - int rc = VINF_SUCCESS; - PRTUTF16 pwszName; - rc = RTStrToUtf16(pszPathBuf, &pwszName); - if (RT_SUCCESS(rc)) - { - pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data); - if (pDir->hDir != INVALID_HANDLE_VALUE) - pDir->fDataUnread = true; - /* theoretical case of an empty directory. */ - else if (GetLastError() == ERROR_NO_MORE_FILES) - pDir->fDataUnread = false; - else - rc = RTErrConvertFromWin32(GetLastError()); - RTUtf16Free(pwszName); - } - - return rc; -} - - -RTDECL(int) RTDirClose(PRTDIR pDir) -{ - /* - * Validate input. - */ - if (!pDir) - return VERR_INVALID_PARAMETER; - if (pDir->u32Magic != RTDIR_MAGIC) - { - AssertMsgFailed(("Invalid pDir=%p\n", pDir)); - return VERR_INVALID_PARAMETER; - } - - /* - * Close the handle. - */ - pDir->u32Magic++; - if (pDir->hDir != INVALID_HANDLE_VALUE) - { - BOOL fRc = FindClose(pDir->hDir); - Assert(fRc); - pDir->hDir = INVALID_HANDLE_VALUE; - } - RTStrFree(pDir->pszName); - pDir->pszName = NULL; - RTMemFree(pDir); - - return VINF_SUCCESS; -} - - -RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry) -{ - /* - * Validate input. - */ - if (!pDir || pDir->u32Magic != RTDIR_MAGIC) - { - AssertMsgFailed(("Invalid pDir=%p\n", pDir)); - return VERR_INVALID_PARAMETER; - } - if (!pDirEntry) - { - AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry)); - return VERR_INVALID_PARAMETER; - } - size_t cbDirEntry = sizeof(*pDirEntry); - if (pcbDirEntry) - { - cbDirEntry = *pcbDirEntry; - if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2])) - { - AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2]))); - return VERR_INVALID_PARAMETER; - } - } - - /* - * Fetch data? - */ - if (!pDir->fDataUnread) - { - RTStrFree(pDir->pszName); - pDir->pszName = NULL; - - BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data); - if (!fRc) - { - int iErr = GetLastError(); - if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES) - return VERR_NO_MORE_FILES; - return RTErrConvertFromWin32(iErr); - } - } - - /* - * Convert the filename to UTF-8. - */ - if (!pDir->pszName) - { - int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName); - if (RT_FAILURE(rc)) - { - pDir->pszName = NULL; - return rc; - } - pDir->cchName = strlen(pDir->pszName); - } - - /* - * Check if we've got enough space to return the data. - */ - const char *pszName = pDir->pszName; - const size_t cchName = pDir->cchName; - const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName; - if (pcbDirEntry) - *pcbDirEntry = cbRequired; - if (cbRequired > cbDirEntry) - return VERR_BUFFER_OVERFLOW; - - /* - * Setup the returned data. - */ - pDir->fDataUnread = false; - pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */ - pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY - ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE; - pDirEntry->cbName = (uint16_t)cchName; - Assert(pDirEntry->cbName == cchName); - memcpy(pDirEntry->szName, pszName, cchName + 1); - - return VINF_SUCCESS; -} - - -RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) -{ - /** @todo Symlinks: Find[First|Next]FileW will return info about - the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */ - /* - * Validate input. - */ - if (!pDir || pDir->u32Magic != RTDIR_MAGIC) - { - AssertMsgFailed(("Invalid pDir=%p\n", pDir)); - return VERR_INVALID_PARAMETER; - } - if (!pDirEntry) - { - AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry)); - return VERR_INVALID_PARAMETER; - } - if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING - || enmAdditionalAttribs > RTFSOBJATTRADD_LAST) - { - AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs)); - return VERR_INVALID_PARAMETER; - } - AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); - size_t cbDirEntry = sizeof(*pDirEntry); - if (pcbDirEntry) - { - cbDirEntry = *pcbDirEntry; - if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2])) - { - AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2]))); - return VERR_INVALID_PARAMETER; - } - } - - /* - * Fetch data? - */ - if (!pDir->fDataUnread) - { - RTStrFree(pDir->pszName); - pDir->pszName = NULL; - - BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data); - if (!fRc) - { - int iErr = GetLastError(); - if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES) - return VERR_NO_MORE_FILES; - return RTErrConvertFromWin32(iErr); - } - } - - /* - * Convert the filename to UTF-8. - */ - if (!pDir->pszName) - { - int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName); - if (RT_FAILURE(rc)) - { - pDir->pszName = NULL; - return rc; - } - pDir->cchName = strlen(pDir->pszName); - } - - /* - * Check if we've got enough space to return the data. - */ - const char *pszName = pDir->pszName; - const size_t cchName = pDir->cchName; - const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName; - if (pcbDirEntry) - *pcbDirEntry = cbRequired; - if (cbRequired > cbDirEntry) - return VERR_BUFFER_OVERFLOW; - - /* - * Setup the returned data. - */ - pDir->fDataUnread = false; - pDirEntry->cbName = (uint16_t)cchName; - Assert(pDirEntry->cbName == cchName); - memcpy(pDirEntry->szName, pszName, cchName + 1); - if (pDir->Data.cAlternateFileName[0]) - { - /* copy and calc length */ - PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName; - PRTUTF16 pwszDst = pDirEntry->wszShortName; - uint32_t off = 0; - while (pwszSrc[off] && off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U) - { - pwszDst[off] = pwszSrc[off]; - off++; - } - pDirEntry->cwcShortName = (uint16_t)off; - - /* zero the rest */ - do - pwszDst[off++] = '\0'; - while (off < RT_ELEMENTS(pDirEntry->wszShortName)); - } - else - { - memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName)); - pDirEntry->cwcShortName = 0; - } - - pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32) - | (uint64_t)pDir->Data.nFileSizeLow; - pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject; - - Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime)); - RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime); - RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime); - RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime); - pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime; - - pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, - pszName, cchName); - - /* - * Requested attributes (we cannot provide anything actually). - */ - switch (enmAdditionalAttribs) - { - case RTFSOBJATTRADD_EASIZE: - pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; - pDirEntry->Info.Attr.u.EASize.cb = 0; - break; - - case RTFSOBJATTRADD_UNIX: - pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; - pDirEntry->Info.Attr.u.Unix.uid = ~0U; - pDirEntry->Info.Attr.u.Unix.gid = ~0U; - pDirEntry->Info.Attr.u.Unix.cHardlinks = 1; - pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */ - pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */ - pDirEntry->Info.Attr.u.Unix.fFlags = 0; - pDirEntry->Info.Attr.u.Unix.GenerationId = 0; - pDirEntry->Info.Attr.u.Unix.Device = 0; - break; - - case RTFSOBJATTRADD_NOTHING: - pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; - break; - - case RTFSOBJATTRADD_UNIX_OWNER: - pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; - pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U; - pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ - break; - - case RTFSOBJATTRADD_UNIX_GROUP: - pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; - pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U; - pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0'; - break; - - default: - AssertMsgFailed(("Impossible!\n")); - return VERR_INTERNAL_ERROR; - } - - return VINF_SUCCESS; -} - - RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename) { /* diff --git a/src/VBox/Runtime/r3/win/direnum-win.cpp b/src/VBox/Runtime/r3/win/direnum-win.cpp new file mode 100644 index 00000000..acc98de3 --- /dev/null +++ b/src/VBox/Runtime/r3/win/direnum-win.cpp @@ -0,0 +1,389 @@ +/* $Id: direnum-win.cpp $ */ +/** @file + * IPRT - Directory Enumeration, Windows. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_DIR +#include <Windows.h> + +#include <iprt/dir.h> +#include <iprt/path.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/file.h> +#include <iprt/log.h> +#include "internal/fs.h" +#include "internal/dir.h" + + +size_t rtDirNativeGetStructSize(const char *pszPath) +{ + NOREF(pszPath); + return sizeof(RTDIR); +} + + +int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf) +{ + /* + * Setup the search expression. + * + * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal() + * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow + * it when adding the wildcard expression. + */ + size_t cbExpr; + const char *pszExpr; + if (pDir->enmFilter == RTDIRFILTER_WINNT) + { + pszExpr = pDir->pszFilter; + cbExpr = pDir->cchFilter + 1; + } + else + { + pszExpr = "*"; + cbExpr = sizeof("*"); + } + if (pDir->cchPath + cbExpr > RTPATH_MAX) + return VERR_FILENAME_TOO_LONG; + memcpy(pszPathBuf + pDir->cchPath, pszExpr, cbExpr); + + + /* + * Attempt opening the search. + */ + int rc = VINF_SUCCESS; + PRTUTF16 pwszName; + rc = RTStrToUtf16(pszPathBuf, &pwszName); + if (RT_SUCCESS(rc)) + { + pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data); + if (pDir->hDir != INVALID_HANDLE_VALUE) + pDir->fDataUnread = true; + else + { + DWORD dwErr = GetLastError(); + /* Theoretical case of an empty directory or more normal case of no matches. */ + if ( dwErr == ERROR_FILE_NOT_FOUND + || dwErr == ERROR_NO_MORE_FILES /* ???*/) + pDir->fDataUnread = false; + else + rc = RTErrConvertFromWin32(GetLastError()); + } + RTUtf16Free(pwszName); + } + + return rc; +} + + +RTDECL(int) RTDirClose(PRTDIR pDir) +{ + /* + * Validate input. + */ + if (!pDir) + return VERR_INVALID_PARAMETER; + if (pDir->u32Magic != RTDIR_MAGIC) + { + AssertMsgFailed(("Invalid pDir=%p\n", pDir)); + return VERR_INVALID_PARAMETER; + } + + /* + * Close the handle. + */ + pDir->u32Magic++; + if (pDir->hDir != INVALID_HANDLE_VALUE) + { + BOOL fRc = FindClose(pDir->hDir); + Assert(fRc); + pDir->hDir = INVALID_HANDLE_VALUE; + } + RTStrFree(pDir->pszName); + pDir->pszName = NULL; + RTMemFree(pDir); + + return VINF_SUCCESS; +} + + +RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry) +{ + /* + * Validate input. + */ + if (!pDir || pDir->u32Magic != RTDIR_MAGIC) + { + AssertMsgFailed(("Invalid pDir=%p\n", pDir)); + return VERR_INVALID_PARAMETER; + } + if (!pDirEntry) + { + AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry)); + return VERR_INVALID_PARAMETER; + } + size_t cbDirEntry = sizeof(*pDirEntry); + if (pcbDirEntry) + { + cbDirEntry = *pcbDirEntry; + if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2])) + { + AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2]))); + return VERR_INVALID_PARAMETER; + } + } + + /* + * Fetch data? + */ + if (!pDir->fDataUnread) + { + RTStrFree(pDir->pszName); + pDir->pszName = NULL; + + BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data); + if (!fRc) + { + int iErr = GetLastError(); + if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES) + return VERR_NO_MORE_FILES; + return RTErrConvertFromWin32(iErr); + } + } + + /* + * Convert the filename to UTF-8. + */ + if (!pDir->pszName) + { + int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName); + if (RT_FAILURE(rc)) + { + pDir->pszName = NULL; + return rc; + } + pDir->cchName = strlen(pDir->pszName); + } + + /* + * Check if we've got enough space to return the data. + */ + const char *pszName = pDir->pszName; + const size_t cchName = pDir->cchName; + const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName; + if (pcbDirEntry) + *pcbDirEntry = cbRequired; + if (cbRequired > cbDirEntry) + return VERR_BUFFER_OVERFLOW; + + /* + * Setup the returned data. + */ + pDir->fDataUnread = false; + pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */ + pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE; + pDirEntry->cbName = (uint16_t)cchName; + Assert(pDirEntry->cbName == cchName); + memcpy(pDirEntry->szName, pszName, cchName + 1); + + return VINF_SUCCESS; +} + + +RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) +{ + /** @todo Symlinks: Find[First|Next]FileW will return info about + the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */ + /* + * Validate input. + */ + if (!pDir || pDir->u32Magic != RTDIR_MAGIC) + { + AssertMsgFailed(("Invalid pDir=%p\n", pDir)); + return VERR_INVALID_PARAMETER; + } + if (!pDirEntry) + { + AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry)); + return VERR_INVALID_PARAMETER; + } + if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING + || enmAdditionalAttribs > RTFSOBJATTRADD_LAST) + { + AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs)); + return VERR_INVALID_PARAMETER; + } + AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); + size_t cbDirEntry = sizeof(*pDirEntry); + if (pcbDirEntry) + { + cbDirEntry = *pcbDirEntry; + if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2])) + { + AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2]))); + return VERR_INVALID_PARAMETER; + } + } + + /* + * Fetch data? + */ + if (!pDir->fDataUnread) + { + RTStrFree(pDir->pszName); + pDir->pszName = NULL; + + BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data); + if (!fRc) + { + int iErr = GetLastError(); + if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES) + return VERR_NO_MORE_FILES; + return RTErrConvertFromWin32(iErr); + } + } + + /* + * Convert the filename to UTF-8. + */ + if (!pDir->pszName) + { + int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName); + if (RT_FAILURE(rc)) + { + pDir->pszName = NULL; + return rc; + } + pDir->cchName = strlen(pDir->pszName); + } + + /* + * Check if we've got enough space to return the data. + */ + const char *pszName = pDir->pszName; + const size_t cchName = pDir->cchName; + const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName; + if (pcbDirEntry) + *pcbDirEntry = cbRequired; + if (cbRequired > cbDirEntry) + return VERR_BUFFER_OVERFLOW; + + /* + * Setup the returned data. + */ + pDir->fDataUnread = false; + pDirEntry->cbName = (uint16_t)cchName; + Assert(pDirEntry->cbName == cchName); + memcpy(pDirEntry->szName, pszName, cchName + 1); + if (pDir->Data.cAlternateFileName[0]) + { + /* copy and calc length */ + PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName; + PRTUTF16 pwszDst = pDirEntry->wszShortName; + uint32_t off = 0; + while (pwszSrc[off] && off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U) + { + pwszDst[off] = pwszSrc[off]; + off++; + } + pDirEntry->cwcShortName = (uint16_t)off; + + /* zero the rest */ + do + pwszDst[off++] = '\0'; + while (off < RT_ELEMENTS(pDirEntry->wszShortName)); + } + else + { + memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName)); + pDirEntry->cwcShortName = 0; + } + + pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32) + | (uint64_t)pDir->Data.nFileSizeLow; + pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject; + + Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime)); + RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime); + RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime); + RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime); + pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime; + + pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, + pszName, cchName); + + /* + * Requested attributes (we cannot provide anything actually). + */ + switch (enmAdditionalAttribs) + { + case RTFSOBJATTRADD_EASIZE: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; + pDirEntry->Info.Attr.u.EASize.cb = 0; + break; + + case RTFSOBJATTRADD_UNIX: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; + pDirEntry->Info.Attr.u.Unix.uid = ~0U; + pDirEntry->Info.Attr.u.Unix.gid = ~0U; + pDirEntry->Info.Attr.u.Unix.cHardlinks = 1; + pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */ + pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */ + pDirEntry->Info.Attr.u.Unix.fFlags = 0; + pDirEntry->Info.Attr.u.Unix.GenerationId = 0; + pDirEntry->Info.Attr.u.Unix.Device = 0; + break; + + case RTFSOBJATTRADD_NOTHING: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; + break; + + case RTFSOBJATTRADD_UNIX_OWNER: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; + pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U; + pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ + break; + + case RTFSOBJATTRADD_UNIX_GROUP: + pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; + pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U; + pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0'; + break; + + default: + AssertMsgFailed(("Impossible!\n")); + return VERR_INTERNAL_ERROR; + } + + return VINF_SUCCESS; +} + diff --git a/src/VBox/Runtime/r3/win/dllmain-win.cpp b/src/VBox/Runtime/r3/win/dllmain-win.cpp index 1646b39e..6efb702a 100644 --- a/src/VBox/Runtime/r3/win/dllmain-win.cpp +++ b/src/VBox/Runtime/r3/win/dllmain-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/env-win.cpp b/src/VBox/Runtime/r3/win/env-win.cpp new file mode 100644 index 00000000..030c6cd7 --- /dev/null +++ b/src/VBox/Runtime/r3/win/env-win.cpp @@ -0,0 +1,268 @@ +/* $Id: env-win.cpp $ */ +/** @file + * IPRT - Environment, Posix. + */ + +/* + * Copyright (C) 2006-2014 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <iprt/env.h> + +#include <iprt/alloca.h> +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/mem.h> + +#include <stdlib.h> +#include <errno.h> + + +RTDECL(bool) RTEnvExistsBad(const char *pszVar) +{ + return RTEnvGetBad(pszVar) != NULL; +} + + +RTDECL(bool) RTEnvExist(const char *pszVar) +{ + return RTEnvExistsBad(pszVar); +} + + +RTDECL(bool) RTEnvExistsUtf8(const char *pszVar) +{ + PRTUTF16 pwszVar; + int rc = RTStrToUtf16(pszVar, &pwszVar); + AssertRCReturn(rc, false); + bool fRet = _wgetenv(pwszVar) != NULL; + RTUtf16Free(pwszVar); + return fRet; +} + + +RTDECL(const char *) RTEnvGetBad(const char *pszVar) +{ + return getenv(pszVar); +} + + +RTDECL(const char *) RTEnvGet(const char *pszVar) +{ + return RTEnvGetBad(pszVar); +} + +RTDECL(int) RTEnvGetUtf8(const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual) +{ + AssertPtrReturn(pszVar, VERR_INVALID_POINTER); + AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER); + AssertReturn(pszValue || !cbValue, VERR_INVALID_PARAMETER); + AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER); + AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER); + + if (pcchActual) + *pcchActual = 0; + + PRTUTF16 pwszVar; + int rc = RTStrToUtf16(pszVar, &pwszVar); + AssertRCReturn(rc, false); + + /** @todo Consider _wgetenv_s or GetEnvironmentVariableW here to avoid the + * potential race with a concurrent _wputenv/_putenv. */ + PCRTUTF16 pwszValue = _wgetenv(pwszVar); + RTUtf16Free(pwszVar); + if (pwszValue) + { + if (cbValue) + rc = RTUtf16ToUtf8Ex(pwszValue, RTSTR_MAX, &pszValue, cbValue, pcchActual); + else + rc = RTUtf16CalcUtf8LenEx(pwszValue, RTSTR_MAX, pcchActual); + } + else + rc = VERR_ENV_VAR_NOT_FOUND; + return rc; +} + + +RTDECL(int) RTEnvPutBad(const char *pszVarEqualValue) +{ + /** @todo putenv is a source memory leaks. deal with this on a per system basis. */ + if (!putenv((char *)pszVarEqualValue)) + return 0; + return RTErrConvertFromErrno(errno); +} + + +RTDECL(int) RTEnvPut(const char *pszVarEqualValue) +{ + return RTEnvPutBad(pszVarEqualValue); +} + + +RTDECL(int) RTEnvPutUtf8(const char *pszVarEqualValue) +{ + PRTUTF16 pwszVarEqualValue; + int rc = RTStrToUtf16(pszVarEqualValue, &pwszVarEqualValue); + if (RT_SUCCESS(rc)) + { + if (!_wputenv(pwszVarEqualValue)) + rc = VINF_SUCCESS; + else + rc = RTErrConvertFromErrno(errno); + RTUtf16Free(pwszVarEqualValue); + } + return rc; +} + + + +RTDECL(int) RTEnvSetBad(const char *pszVar, const char *pszValue) +{ + /* make a local copy and feed it to putenv. */ + const size_t cchVar = strlen(pszVar); + const size_t cchValue = strlen(pszValue); + char *pszTmp = (char *)alloca(cchVar + cchValue + 2 + !*pszValue); + memcpy(pszTmp, pszVar, cchVar); + pszTmp[cchVar] = '='; + if (*pszValue) + memcpy(pszTmp + cchVar + 1, pszValue, cchValue + 1); + else + { + pszTmp[cchVar + 1] = ' '; /* wrong, but putenv will remove it otherwise. */ + pszTmp[cchVar + 2] = '\0'; + } + + if (!putenv(pszTmp)) + return 0; + return RTErrConvertFromErrno(errno); +} + + +RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue) +{ + return RTEnvSetBad(pszVar, pszValue); +} + +RTDECL(int) RTEnvSetUtf8(const char *pszVar, const char *pszValue) +{ + size_t cwcVar; + int rc = RTStrCalcUtf16LenEx(pszVar, RTSTR_MAX, &cwcVar); + if (RT_SUCCESS(rc)) + { + size_t cwcValue; + rc = RTStrCalcUtf16LenEx(pszVar, RTSTR_MAX, &cwcValue); + if (RT_SUCCESS(rc)) + { + PRTUTF16 pwszTmp = (PRTUTF16)RTMemTmpAlloc((cwcVar + 1 + cwcValue + 1) * sizeof(RTUTF16)); + if (pwszTmp) + { + rc = RTStrToUtf16Ex(pszVar, RTSTR_MAX, &pwszTmp, cwcVar + 1, NULL); + if (RT_SUCCESS(rc)) + { + PRTUTF16 pwszTmpValue = &pwszTmp[cwcVar]; + *pwszTmpValue++ = '='; + rc = RTStrToUtf16Ex(pszValue, RTSTR_MAX, &pwszTmpValue, cwcValue + 1, NULL); + if (RT_SUCCESS(rc)) + { + if (!_wputenv(pwszTmp)) + rc = VINF_SUCCESS; + else + rc = RTErrConvertFromErrno(errno); + } + } + RTMemTmpFree(pwszTmp); + } + else + rc = VERR_NO_TMP_MEMORY; + } + } + return rc; +} + + +RTDECL(int) RTEnvUnsetBad(const char *pszVar) +{ + AssertReturn(!strchr(pszVar, '='), VERR_INVALID_PARAMETER); + + /* + * Check that it exists first. + */ + if (!RTEnvExist(pszVar)) + return VINF_ENV_VAR_NOT_FOUND; + + /* + * Ok, try remove it. + */ +#ifdef RT_OS_WINDOWS + /* Use putenv(var=) since Windows does not have unsetenv(). */ + size_t cchVar = strlen(pszVar); + char *pszBuf = (char *)alloca(cchVar + 2); + memcpy(pszBuf, pszVar, cchVar); + pszBuf[cchVar] = '='; + pszBuf[cchVar + 1] = '\0'; + + if (!putenv(pszBuf)) + return VINF_SUCCESS; + +#else + /* This is the preferred function as putenv() like used above does neither work on Solaris nor on Darwin. */ + if (!unsetenv((char*)pszVar)) + return VINF_SUCCESS; +#endif + + return RTErrConvertFromErrno(errno); +} + + +RTDECL(int) RTEnvUnset(const char *pszVar) +{ + return RTEnvUnsetBad(pszVar); +} + + +RTDECL(int) RTEnvUnsetUtf8(const char *pszVar) +{ + size_t cwcVar; + int rc = RTStrCalcUtf16LenEx(pszVar, RTSTR_MAX, &cwcVar); + if (RT_SUCCESS(rc)) + { + PRTUTF16 pwszTmp = (PRTUTF16)RTMemTmpAlloc((cwcVar + 1 + 1) * sizeof(RTUTF16)); + if (pwszTmp) + { + rc = RTStrToUtf16Ex(pszVar, RTSTR_MAX, &pwszTmp, cwcVar + 1, NULL); + if (RT_SUCCESS(rc)) + { + pwszTmp[cwcVar] = '='; + pwszTmp[cwcVar + 1] = '\0'; + if (!_wputenv(pwszTmp)) + rc = VINF_SUCCESS; + else + rc = RTErrConvertFromErrno(errno); + } + RTMemTmpFree(pwszTmp); + } + } + return rc; +} + diff --git a/src/VBox/Runtime/r3/win/fileaio-win.cpp b/src/VBox/Runtime/r3/win/fileaio-win.cpp index 95e20e12..73c99a7e 100644 --- a/src/VBox/Runtime/r3/win/fileaio-win.cpp +++ b/src/VBox/Runtime/r3/win/fileaio-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -72,6 +72,8 @@ typedef struct RTFILEAIOCTXINTERNAL volatile bool fWokenUp; /** Flag whether the thread is currently waiting. */ volatile bool fWaiting; + /** Flags given during creation. */ + uint32_t fFlags; /** Magic value (RTFILEAIOCTX_MAGIC). */ uint32_t u32Magic; } RTFILEAIOCTXINTERNAL; @@ -266,10 +268,12 @@ RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered) return rc; } -RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags) { PRTFILEAIOCTXINTERNAL pCtxInt; AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL)); if (RT_UNLIKELY(!pCtxInt)) @@ -285,7 +289,8 @@ RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax) return VERR_NO_MEMORY; } - pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; + pCtxInt->fFlags = fFlags; + pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC; *phAioCtx = (RTFILEAIOCTX)pCtxInt; @@ -398,7 +403,8 @@ RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL /* * Can't wait if there are no requests around. */ - if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0)) + if ( RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0) + && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS)) return VERR_FILE_AIO_NO_REQUEST; /* Wait for at least one. */ diff --git a/src/VBox/Runtime/r3/win/fs-win.cpp b/src/VBox/Runtime/r3/win/fs-win.cpp index c0fa65c3..586444e4 100644 --- a/src/VBox/Runtime/r3/win/fs-win.cpp +++ b/src/VBox/Runtime/r3/win/fs-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -319,6 +319,9 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper pProperties->fReadOnly = !!(dwFlags & FILE_READ_ONLY_VOLUME); pProperties->fSupportsUnicode = !!(dwFlags & 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. */ pProperties->fRemote = false; /* no idea yet */ } else diff --git a/src/VBox/Runtime/r3/win/init-win.cpp b/src/VBox/Runtime/r3/win/init-win.cpp new file mode 100644 index 00000000..e40adf6a --- /dev/null +++ b/src/VBox/Runtime/r3/win/init-win.cpp @@ -0,0 +1,273 @@ +/* $Id: init-win.cpp $ */ +/** @file + * IPRT - Init Ring-3, Windows Specific Code. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP RTLOGGROUP_DEFAULT +#include <Windows.h> +#ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR +# define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x200 +# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 +#endif + +#include "internal-r3-win.h" +#include <iprt/initterm.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/string.h> +#include "../init.h" + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Windows DLL loader protection level. */ +DECLHIDDEN(RTR3WINLDRPROT) g_enmWinLdrProt = RTR3WINLDRPROT_NONE; +/** Our simplified windows version. */ +DECLHIDDEN(RTWINOSTYPE) g_enmWinVer = kRTWinOSType_UNKNOWN; +/** Extended windows version information. */ +DECLHIDDEN(OSVERSIONINFOEX) g_WinOsInfoEx; +/** The native kernel32.dll handle. */ +DECLHIDDEN(HMODULE) g_hModKernel32 = NULL; +/** The native ntdll.dll handle. */ +DECLHIDDEN(HMODULE) g_hModNtDll = NULL; + + + +/** + * Translates OSVERSIONINOFEX into a Windows OS type. + * + * @returns The Windows OS type. + * @param pOSInfoEx The OS info returned by Windows. + * + * @remarks This table has been assembled from Usenet postings, personal + * observations, and reading other people's code. Please feel + * free to add to it or correct it. + * <pre> + dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber +95 1 4 0 950 +95 SP1 1 4 0 >950 && <=1080 +95 OSR2 1 4 <10 >1080 +98 1 4 10 1998 +98 SP1 1 4 10 >1998 && <2183 +98 SE 1 4 10 >=2183 +ME 1 4 90 3000 + +NT 3.51 2 3 51 1057 +NT 4 2 4 0 1381 +2000 2 5 0 2195 +XP 2 5 1 2600 +2003 2 5 2 3790 +Vista 2 6 0 + +CE 1.0 3 1 0 +CE 2.0 3 2 0 +CE 2.1 3 2 1 +CE 3.0 3 3 0 +</pre> + */ +static RTWINOSTYPE rtR3InitWinSimplifiedVersion(OSVERSIONINFOEX const *pOSInfoEx) +{ + RTWINOSTYPE enmVer = kRTWinOSType_UNKNOWN; + BYTE const bProductType = pOSInfoEx->wProductType; + DWORD const dwPlatformId = pOSInfoEx->dwPlatformId; + DWORD const dwMinorVersion = pOSInfoEx->dwMinorVersion; + DWORD const dwMajorVersion = pOSInfoEx->dwMajorVersion; + DWORD const dwBuildNumber = pOSInfoEx->dwBuildNumber & 0xFFFF; /* Win 9x needs this. */ + + if ( dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + && dwMajorVersion == 4) + { + if ( dwMinorVersion < 10 + && dwBuildNumber == 950) + enmVer = kRTWinOSType_95; + else if ( dwMinorVersion < 10 + && dwBuildNumber > 950 + && dwBuildNumber <= 1080) + enmVer = kRTWinOSType_95SP1; + else if ( dwMinorVersion < 10 + && dwBuildNumber > 1080) + enmVer = kRTWinOSType_95OSR2; + else if ( dwMinorVersion == 10 + && dwBuildNumber == 1998) + enmVer = kRTWinOSType_98; + else if ( dwMinorVersion == 10 + && dwBuildNumber > 1998 + && dwBuildNumber < 2183) + enmVer = kRTWinOSType_98SP1; + else if ( dwMinorVersion == 10 + && dwBuildNumber >= 2183) + enmVer = kRTWinOSType_98SE; + else if (dwMinorVersion == 90) + enmVer = kRTWinOSType_ME; + } + else if (dwPlatformId == VER_PLATFORM_WIN32_NT) + { + if ( dwMajorVersion == 3 + && dwMinorVersion == 51) + enmVer = kRTWinOSType_NT351; + else if ( dwMajorVersion == 4 + && dwMinorVersion == 0) + enmVer = kRTWinOSType_NT4; + else if ( dwMajorVersion == 5 + && dwMinorVersion == 0) + enmVer = kRTWinOSType_2K; + else if ( dwMajorVersion == 5 + && dwMinorVersion == 1) + enmVer = kRTWinOSType_XP; + else if ( dwMajorVersion == 5 + && dwMinorVersion == 2) + enmVer = kRTWinOSType_2003; + else if ( dwMajorVersion == 6 + && dwMinorVersion == 0) + { + if (bProductType != VER_NT_WORKSTATION) + enmVer = kRTWinOSType_2008; + else + enmVer = kRTWinOSType_VISTA; + } + else if ( dwMajorVersion == 6 + && dwMinorVersion == 1) + enmVer = kRTWinOSType_7; + else if ( dwMajorVersion == 6 + && dwMinorVersion == 2) + enmVer = kRTWinOSType_8; + else if ( dwMajorVersion == 6 + && dwMinorVersion == 3) + enmVer = kRTWinOSType_81; + else + enmVer = kRTWinOSType_NT_UNKNOWN; + } + + return enmVer; +} + + +DECLHIDDEN(int) rtR3InitNativeObtrusiveWorker(void) +{ + /* + * Disable error popups. + */ + UINT fOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX | fOldErrMode); + + /* + * Query the Windows version. + * ASSUMES OSVERSIONINFOEX starts with the exact same layout as OSVERSIONINFO (safe). + */ + AssertCompileMembersSameSizeAndOffset(OSVERSIONINFOEX, szCSDVersion, OSVERSIONINFO, szCSDVersion); + AssertCompileMemberOffset(OSVERSIONINFOEX, wServicePackMajor, sizeof(OSVERSIONINFO)); + RT_ZERO(g_WinOsInfoEx); + g_WinOsInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (!GetVersionExA((POSVERSIONINFOA)&g_WinOsInfoEx)) + { + /* Fallback, just get the basic info. */ + RT_ZERO(g_WinOsInfoEx); + g_WinOsInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionExA((POSVERSIONINFOA)&g_WinOsInfoEx)) + Assert(g_WinOsInfoEx.dwPlatformId != VER_PLATFORM_WIN32_NT || g_WinOsInfoEx.dwMajorVersion < 5); + else + { + AssertBreakpoint(); + RT_ZERO(g_WinOsInfoEx); + } + } + if (g_WinOsInfoEx.dwOSVersionInfoSize) + g_enmWinVer = rtR3InitWinSimplifiedVersion(&g_WinOsInfoEx); + + /* + * Restrict DLL searching for the process on windows versions which allow + * us to do so. + * - The first trick works on XP SP1+ and disables the searching of the + * current directory. + * - The second trick is W7 w/ KB2533623 and W8+, it restrict the DLL + * searching to the application directory and the System32 directory. + */ + int rc = VINF_SUCCESS; + + typedef BOOL (WINAPI *PFNSETDLLDIRECTORY)(LPCWSTR); + PFNSETDLLDIRECTORY pfnSetDllDir = (PFNSETDLLDIRECTORY)GetProcAddress(g_hModKernel32, "SetDllDirectoryW"); + if (pfnSetDllDir) + { + if (pfnSetDllDir(L"")) + g_enmWinLdrProt = RTR3WINLDRPROT_NO_CWD; + else + rc = VERR_INTERNAL_ERROR_3; + } + + /** @bugref 6861: Observed GUI issues on Vista (32-bit and 64-bit). */ + if (g_enmWinVer > kRTWinOSType_VISTA) + { + typedef BOOL(WINAPI *PFNSETDEFAULTDLLDIRECTORIES)(DWORD); + PFNSETDEFAULTDLLDIRECTORIES pfnSetDefDllDirs; + pfnSetDefDllDirs = (PFNSETDEFAULTDLLDIRECTORIES)GetProcAddress(g_hModKernel32, "SetDefaultDllDirectories"); + if (pfnSetDefDllDirs) + { + if (pfnSetDefDllDirs(LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32)) + g_enmWinLdrProt = RTR3WINLDRPROT_SAFE; + else if (RT_SUCCESS(rc)) + rc = VERR_INTERNAL_ERROR_4; + } + } + + return rc; +} + + +DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags) +{ + /* + * Make sure we've got the handles of the two main Windows NT dlls. + */ + g_hModKernel32 = GetModuleHandleW(L"kernel32.dll"); + if (g_hModKernel32 == NULL) + return VERR_INTERNAL_ERROR_2; + g_hModNtDll = GetModuleHandleW(L"ntdll.dll"); + if (g_hModNtDll == NULL) + return VERR_INTERNAL_ERROR_2; + + int rc = VINF_SUCCESS; + if (!(fFlags & RTR3INIT_FLAGS_UNOBTRUSIVE)) + rc = rtR3InitNativeObtrusiveWorker(); + + return rc; +} + + +DECLHIDDEN(void) rtR3InitNativeObtrusive(void) +{ + rtR3InitNativeObtrusiveWorker(); +} + + +DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags) +{ + /* Nothing to do here. */ + return VINF_SUCCESS; +} + diff --git a/src/VBox/Runtime/r3/win/internal-r3-win.h b/src/VBox/Runtime/r3/win/internal-r3-win.h new file mode 100644 index 00000000..efec00a1 --- /dev/null +++ b/src/VBox/Runtime/r3/win/internal-r3-win.h @@ -0,0 +1,72 @@ + +#ifndef ___internal_r3_win_h +#define ___internal_r3_win_h + +#include "internal/iprt.h" +#include <iprt/types.h> + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Windows OS type as determined by rtSystemWinOSType(). + * + * @note ASSUMPTIONS are made regarding ordering. Win 9x should come first, then + * NT. The Win9x and NT versions should internally be ordered in ascending + * version/code-base order. + */ +typedef enum RTWINOSTYPE +{ + kRTWinOSType_UNKNOWN = 0, + kRTWinOSType_9XFIRST = 1, + kRTWinOSType_95 = kRTWinOSType_9XFIRST, + kRTWinOSType_95SP1, + kRTWinOSType_95OSR2, + kRTWinOSType_98, + kRTWinOSType_98SP1, + kRTWinOSType_98SE, + kRTWinOSType_ME, + kRTWinOSType_9XLAST = 99, + kRTWinOSType_NTFIRST = 100, + kRTWinOSType_NT31 = kRTWinOSType_NTFIRST, + kRTWinOSType_NT351, + kRTWinOSType_NT4, + kRTWinOSType_2K, + kRTWinOSType_XP, + kRTWinOSType_2003, + kRTWinOSType_VISTA, + kRTWinOSType_2008, + kRTWinOSType_7, + kRTWinOSType_8, + kRTWinOSType_81, + kRTWinOSType_NT_UNKNOWN = 199, + kRTWinOSType_NT_LAST = kRTWinOSType_UNKNOWN +} RTWINOSTYPE; + +/** + * Windows loader protection level. + */ +typedef enum RTR3WINLDRPROT +{ + RTR3WINLDRPROT_INVALID = 0, + RTR3WINLDRPROT_NONE, + RTR3WINLDRPROT_NO_CWD, + RTR3WINLDRPROT_SAFE +} RTR3WINLDRPROT; + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +extern DECLHIDDEN(RTR3WINLDRPROT) g_enmWinLdrProt; +extern DECLHIDDEN(RTWINOSTYPE) g_enmWinVer; +#ifdef _WINDEF_ +extern DECLHIDDEN(HMODULE) g_hModKernel32; +extern DECLHIDDEN(HMODULE) g_hModNtDll; +extern DECLHIDDEN(OSVERSIONINFOEX) g_WinOsInfoEx; +#endif + + +#endif + diff --git a/src/VBox/Runtime/r3/win/ldrNative-win.cpp b/src/VBox/Runtime/r3/win/ldrNative-win.cpp index 54016958..8b26ab2c 100644 --- a/src/VBox/Runtime/r3/win/ldrNative-win.cpp +++ b/src/VBox/Runtime/r3/win/ldrNative-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -31,10 +31,17 @@ #include <Windows.h> #include <iprt/ldr.h> +#include "internal/iprt.h" + +#include <iprt/alloca.h> #include <iprt/assert.h> -#include <iprt/path.h> #include <iprt/err.h> -#include <iprt/alloca.h> +#include <iprt/file.h> +#include <iprt/log.h> +#include <iprt/path.h> +#include <iprt/string.h> + +#include <iprt/once.h> #include <iprt/string.h> #include "internal/ldr.h" @@ -42,7 +49,10 @@ int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlags, PRTERRINFO pErrInfo) { Assert(sizeof(*phHandle) >= sizeof(HMODULE)); - AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); + AssertReturn(fFlags == 0 || fFlags == RTLDRLOAD_FLAGS_NO_UNLOAD, VERR_INVALID_PARAMETER); + AssertLogRelMsgReturn(RTPathStartsWithRoot(pszFilename), /* Relative names will still be applied to the search path. */ + ("pszFilename='%s'\n", pszFilename), + VERR_INTERNAL_ERROR_2); /* * Do we need to add an extension? @@ -72,7 +82,7 @@ int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlag * Try figure why it failed to load. */ DWORD dwErr = GetLastError(); - int rc = RTErrConvertFromWin32(dwErr); + int rc = RTErrConvertFromWin32(dwErr); return RTErrInfoSetF(pErrInfo, rc, "GetLastError=%u", dwErr); } @@ -94,7 +104,8 @@ DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSy DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod) { PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod; - if (FreeLibrary((HMODULE)pModNative->hNative)) + if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD) + || FreeLibrary((HMODULE)pModNative->hNative)) { pModNative->hNative = (uintptr_t)INVALID_HANDLE_VALUE; return VINF_SUCCESS; @@ -102,3 +113,34 @@ DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod) return RTErrConvertFromWin32(GetLastError()); } + +int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod) +{ + /* + * We only try the System32 directory. + */ + WCHAR wszSysDir[MAX_PATH]; + UINT cwcSysDir = GetSystemDirectoryW(wszSysDir, MAX_PATH); + if (cwcSysDir >= MAX_PATH) + return VERR_FILENAME_TOO_LONG; + + char szPath[RTPATH_MAX]; + char *pszPath = szPath; + int rc = RTUtf16ToUtf8Ex(wszSysDir, RTSTR_MAX, &pszPath, sizeof(szPath), NULL); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(szPath, sizeof(szPath), pszFilename); + if (pszExt && RT_SUCCESS(rc)) + rc = RTStrCat(szPath, sizeof(szPath), pszExt); + if (RT_SUCCESS(rc)) + { + if (RTFileExists(szPath)) + rc = RTLdrLoadEx(szPath, phLdrMod, fFlags, NULL); + else + rc = VERR_MODULE_NOT_FOUND; + } + } + + return rc; +} + diff --git a/src/VBox/Runtime/r3/win/localipc-win.cpp b/src/VBox/Runtime/r3/win/localipc-win.cpp index 15ff6f8b..a25b9cac 100644 --- a/src/VBox/Runtime/r3/win/localipc-win.cpp +++ b/src/VBox/Runtime/r3/win/localipc-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -41,15 +41,17 @@ #include <Windows.h> #include <sddl.h> -#include <iprt/localipc.h> -#include <iprt/thread.h> -#include <iprt/critsect.h> #include <iprt/alloc.h> +#include <iprt/asm.h> #include <iprt/assert.h> -#include <iprt/param.h> +#include <iprt/critsect.h> #include <iprt/err.h> +#include <iprt/ldr.h> +#include <iprt/localipc.h> +#include <iprt/param.h> #include <iprt/string.h> -#include <iprt/asm.h> +#include <iprt/thread.h> +#include <iprt/time.h> #include "internal/magics.h" @@ -66,7 +68,9 @@ * * Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes * the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded - * value 0x0012019b in the 2nd ACE. It expands to: + * value 0x0012019b in the client ACE. The server-side still needs + * setting FILE_CREATE_PIPE_INSTANCE although. + * It expands to: * 0x00000001 - FILE_READ_DATA * 0x00000008 - FILE_READ_EA * 0x00000080 - FILE_READ_ATTRIBUTES @@ -75,11 +79,12 @@ * 0x00000002 - FILE_WRITE_DATA * 0x00000010 - FILE_WRITE_EA * 0x00000100 - FILE_WRITE_ATTRIBUTES - * 0x0012019b - * or FILE_GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_CREATE_PIPE_INSTANCE) + * = 0x0012019b (client) + * + (only for server): + * 0x00000004 - FILE_CREATE_PIPE_INSTANCE + * = 0x0012019f * - * @todo Double check this! - * @todo Drop the EA rights too? Since they doesn't mean anything to PIPS according to the docs. + * @todo Triple check this! * @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate? * @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking * it just to get progress - the service runs as local system. @@ -88,12 +93,19 @@ * is to go the annoying route of OpenProcessToken, QueryTokenInformation, * ConvertSidToStringSid and then use the result... Suggestions are very welcome */ -#define RTLOCALIPC_WIN_SDDL \ - SDDL_DACL SDDL_DELIMINATOR \ +#define RTLOCALIPC_WIN_SDDL_BASE \ + SDDL_DACL SDDL_DELIMINATOR \ SDDL_ACE_BEGIN SDDL_ACCESS_DENIED ";;" SDDL_GENERIC_ALL ";;;" SDDL_NETWORK SDDL_ACE_END \ - SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END \ SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END +#define RTLOCALIPC_WIN_SDDL_SERVER \ + RTLOCALIPC_WIN_SDDL_BASE \ + SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019f" ";;;" SDDL_EVERYONE SDDL_ACE_END + +#define RTLOCALIPC_WIN_SDDL_CLIENT \ + RTLOCALIPC_WIN_SDDL_BASE \ + SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END + // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \ // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";CIOI;" SDDL_GENERIC_ALL ";;;" SDDL_CREATOR_OWNER SDDL_ACE_END // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END @@ -138,24 +150,41 @@ typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT; typedef struct RTLOCALIPCSESSIONINT { /** The magic (RTLOCALIPCSESSION_MAGIC). */ - uint32_t u32Magic; + uint32_t u32Magic; /** Critical section protecting the structure. */ - RTCRITSECT CritSect; + RTCRITSECT CritSect; /** The number of references to the instance. * @remarks The reference counting isn't race proof. */ - uint32_t volatile cRefs; + uint32_t volatile cRefs; + /** Set if there is already pending I/O. */ + bool fIOPending; + /** Set if the zero byte read that the poll code using is pending. */ + bool fZeroByteRead; /** Indicates that there is a pending cancel request. */ - bool volatile fCancelled; + bool volatile fCancelled; /** The name pipe handle. */ - HANDLE hNmPipe; + HANDLE hNmPipe; /** The handle to the event object we're using for overlapped I/O. */ - HANDLE hEvent; + HANDLE hEvent; /** The overlapped I/O structure. */ - OVERLAPPED OverlappedIO; + OVERLAPPED OverlappedIO; + /** Bounce buffer for writes. */ + uint8_t *pbBounceBuf; + /** Amount of used buffer space. */ + size_t cbBounceBufUsed; + /** Amount of allocated buffer space. */ + size_t cbBounceBufAlloc; + /** Buffer for the zero byte read. + * Used in RTLocalIpcSessionWaitForData(). */ + uint8_t abBuf[8]; } RTLOCALIPCSESSIONINT; /** Pointer to a local IPC session instance (Windows). */ typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT; +typedef BOOL WINAPI FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR(LPCTSTR, DWORD, PSECURITY_DESCRIPTOR, PULONG); +typedef FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR + *PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR; /* No, nobody fell on the keyboard, really! */ + /******************************************************************************* * Internal Functions * @@ -164,52 +193,124 @@ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE /** + * Builds and allocates the security descriptor required for securing the local pipe. + * + * @return IPRT status code. + * @param ppDesc Where to store the allocated security descriptor on success. + * Must be free'd using LocalFree(). + */ +static int rtLocalIpcServerWinAllocSecurityDescriptior(PSECURITY_DESCRIPTOR *ppDesc, bool fServer) +{ + /** @todo Stuff this into RTInitOnce? Later. */ + PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR + pfnConvertStringSecurityDescriptorToSecurityDescriptor = NULL; + + RTLDRMOD hAdvApi32 = NIL_RTLDRMOD; + int rc = RTLdrLoadSystem("Advapi32.dll", true /*fNoUnload*/, &hAdvApi32); + if (RT_SUCCESS(rc)) + rc = RTLdrGetSymbol(hAdvApi32, "ConvertStringSecurityDescriptorToSecurityDescriptorW", + (void**)&pfnConvertStringSecurityDescriptorToSecurityDescriptor); + + PSECURITY_DESCRIPTOR pSecDesc = NULL; + if (RT_SUCCESS(rc)) + { + AssertPtr(pfnConvertStringSecurityDescriptorToSecurityDescriptor); + + /* + * We'll create a security descriptor from a SDDL that denies + * access to network clients (this is local IPC after all), it + * makes some further restrictions to prevent non-authenticated + * users from screwing around. + */ + PRTUTF16 pwszSDDL; + rc = RTStrToUtf16(fServer + ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT, &pwszSDDL); + if (RT_SUCCESS(rc)) + { + if (!pfnConvertStringSecurityDescriptorToSecurityDescriptor((LPCTSTR)pwszSDDL, + SDDL_REVISION_1, + &pSecDesc, + NULL)) + { + rc = RTErrConvertFromWin32(GetLastError()); + } + + RTUtf16Free(pwszSDDL); + } + } + else + { + /* Windows OSes < W2K SP2 not supported for now, bail out. */ + /** @todo Implement me! */ + rc = VERR_NOT_SUPPORTED; + } + + if (hAdvApi32 != NIL_RTLDRMOD) + RTLdrClose(hAdvApi32); + + if (RT_SUCCESS(rc)) + { + AssertPtr(pSecDesc); + *ppDesc = pSecDesc; + } + + return rc; +} + +/** * Creates a named pipe instance. * * This is used by both RTLocalIpcServerCreate and RTLocalIpcServerListen. * - * @returns Windows error code, that is NO_ERROR and *phNmPipe on success and some ERROR_* on failure. - * + * @return IPRT status code. * @param phNmPipe Where to store the named pipe handle on success. This * will be set to INVALID_HANDLE_VALUE on failure. * @param pszFullPipeName The full named pipe name. * @param fFirst Set on the first call (from RTLocalIpcServerCreate), otherwise clear. * Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag. */ -static DWORD rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst) +static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst) { *phNmPipe = INVALID_HANDLE_VALUE; - /* - * We'll create a security descriptor from a SDDL that denies - * access to network clients (this is local IPC after all), it - * makes some further restrictions to prevent non-authenticated - * users from screwing around. - */ - DWORD err; - PSECURITY_DESCRIPTOR pSecDesc = NULL; -#if 0 /** @todo dynamically resolve this as it is the only thing that prevents - * loading IPRT on NT4. */ - if (ConvertStringSecurityDescriptorToSecurityDescriptor(RTLOCALIPC_WIN_SDDL, - SDDL_REVISION_1, - &pSecDesc, - NULL)) -#else - AssertFatalFailed(); - SetLastError(-1); - if (0) -#endif + PSECURITY_DESCRIPTOR pSecDesc; + int rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, fFirst /* Server? */); + if (RT_SUCCESS(rc)) { SECURITY_ATTRIBUTES SecAttrs; - SecAttrs.nLength = sizeof(SecAttrs); + SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES); SecAttrs.lpSecurityDescriptor = pSecDesc; SecAttrs.bInheritHandle = FALSE; DWORD fOpenMode = PIPE_ACCESS_DUPLEX | PIPE_WAIT | FILE_FLAG_OVERLAPPED; - if (fFirst) - fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; /* Note! Requires W2K SP2+. */ + + bool fSupportsFirstInstance = false; + + OSVERSIONINFOEX OSInfoEx; + RT_ZERO(OSInfoEx); + OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx) + && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + if ( /* Vista+. */ + OSInfoEx.dwMajorVersion >= 6 + /* Windows XP+. */ + || ( OSInfoEx.dwMajorVersion == 5 + && OSInfoEx.dwMinorVersion > 0) + /* Windows 2000. */ + || ( OSInfoEx.dwMajorVersion == 5 + && OSInfoEx.dwMinorVersion == 0 + && OSInfoEx.wServicePackMajor >= 2)) + { + /* Requires at least W2K (5.0) SP2+. This is non-fatal. */ + fSupportsFirstInstance = true; + } + } + + if (fFirst && fSupportsFirstInstance) + fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; HANDLE hNmPipe = CreateNamedPipe(pszFullPipeName, /* lpName */ fOpenMode, /* dwOpenMode */ @@ -219,19 +320,16 @@ static DWORD rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char PAGE_SIZE, /* nInBufferSize (ditto) */ 30*1000, /* nDefaultTimeOut = 30 sec */ &SecAttrs); /* lpSecurityAttributes */ - err = GetLastError(); LocalFree(pSecDesc); if (hNmPipe != INVALID_HANDLE_VALUE) { *phNmPipe = hNmPipe; - return NO_ERROR; } + else + rc = RTErrConvertFromWin32(GetLastError()); } - else - err = GetLastError(); - AssertReturn(err != NO_ERROR, ERROR_GEN_FAILURE); - return err; + return rc; } @@ -244,8 +342,7 @@ RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszNa AssertPtrReturn(pszName, VERR_INVALID_POINTER); AssertReturn(*pszName, VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & ~(RTLOCALIPC_FLAGS_VALID_MASK)), VERR_INVALID_PARAMETER); - - AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_NOT_IMPLEMENTED); /** @todo implement !RTLOCALIPC_FLAGS_MULTI_SESSION */ + AssertReturn((fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION), VERR_INVALID_PARAMETER); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */ /* * Allocate and initialize the instance data. @@ -263,24 +360,30 @@ RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszNa int rc = RTCritSectInit(&pThis->CritSect); if (RT_SUCCESS(rc)) { - DWORD err = NO_ERROR; - pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/); + pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, + FALSE /*bInitialState*/, NULL /*lpName*/); if (pThis->hEvent != NULL) { - memset(&pThis->OverlappedIO, 0, sizeof(pThis->OverlappedIO)); + RT_ZERO(pThis->OverlappedIO); pThis->OverlappedIO.Internal = STATUS_PENDING; pThis->OverlappedIO.hEvent = pThis->hEvent; - err = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, pThis->szName, true /* fFirst */); - if (err == NO_ERROR) + rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, + pThis->szName, true /* fFirst */); + if (RT_SUCCESS(rc)) { *phServer = pThis; return VINF_SUCCESS; } + + BOOL fRc = CloseHandle(pThis->hEvent); + AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); } else - err = GetLastError(); - rc = RTErrConvertFromWin32(err); + rc = RTErrConvertFromWin32(GetLastError()); + + int rc2 = RTCritSectDelete(&pThis->CritSect); + AssertRC(rc2); } RTMemFree(pThis); return rc; @@ -327,9 +430,10 @@ RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer) RTCritSectEnter(&pThis->CritSect); ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC); ASMAtomicUoWriteBool(&pThis->fCancelled, true); + Assert(pThis->cRefs); pThis->cRefs--; - if (pThis->cRefs > 0) + if (pThis->cRefs) { BOOL fRc = SetEvent(pThis->hEvent); AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); @@ -371,23 +475,23 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION /* * Try connect a client. We need to use overlapped I/O here because - * of the cancellation a by RTLocalIpcServerCancel and RTLocalIpcServerDestroy. + * of the cancellation done by RTLocalIpcServerCancel and RTLocalIpcServerDestroy. */ SetLastError(NO_ERROR); BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO); - DWORD err = fRc ? NO_ERROR : GetLastError(); + DWORD dwErr = fRc ? NO_ERROR : GetLastError(); if ( !fRc - && err == ERROR_IO_PENDING) + && dwErr == ERROR_IO_PENDING) { WaitForSingleObject(pThis->hEvent, INFINITE); DWORD dwIgnored; fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/); - err = fRc ? NO_ERROR : GetLastError(); + dwErr = fRc ? NO_ERROR : GetLastError(); } RTCritSectEnter(&pThis->CritSect); - if ( !pThis->fCancelled - && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC) + if ( !pThis->fCancelled /* Event signalled but not cancelled? */ + && pThis->u32Magic == RTLOCALIPCSERVER_MAGIC) { /* * Still alive, some error or an actual client. @@ -396,12 +500,12 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION * replaces the current one for the server. The current pipe instance * will be assigned to the client session. */ - if ( fRc - || err == ERROR_PIPE_CONNECTED) + if ( fRc + || dwErr == ERROR_PIPE_CONNECTED) { HANDLE hNmPipe; - DWORD err = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->szName, false /* fFirst */); - if (err == NO_ERROR) + rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->szName, false /* fFirst */); + if (RT_SUCCESS(rc)) { HANDLE hNmPipeSession = pThis->hNmPipe; /* consumed */ pThis->hNmPipe = hNmPipe; @@ -413,13 +517,12 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION * We failed to create a new instance for the server, disconnect * the client and fail. Don't try service the client here. */ - rc = RTErrConvertFromWin32(err); fRc = DisconnectNamedPipe(pThis->hNmPipe); AssertMsg(fRc, ("%d\n", GetLastError())); } } else - rc = RTErrConvertFromWin32(err); + rc = RTErrConvertFromWin32(dwErr); } else { @@ -430,9 +533,9 @@ RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION * in the this thread) or disconnect the client. */ if ( fRc - || err == ERROR_PIPE_CONNECTED) + || dwErr == ERROR_PIPE_CONNECTED) fRc = DisconnectNamedPipe(pThis->hNmPipe); - else if (err == ERROR_IO_PENDING) + else if (dwErr == ERROR_IO_PENDING) fRc = CancelIo(pThis->hNmPipe); else fRc = TRUE; @@ -464,15 +567,17 @@ RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer) * Enter the critical section, then set the cancellation flag * and signal the event (to wake up anyone in/at WaitForSingleObject). */ - RTCritSectEnter(&pThis->CritSect); - - ASMAtomicUoWriteBool(&pThis->fCancelled, true); - BOOL fRc = SetEvent(pThis->hEvent); - AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + ASMAtomicUoWriteBool(&pThis->fCancelled, true); + BOOL fRc = SetEvent(pThis->hEvent); + AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); - RTCritSectLeave(&pThis->CritSect); + rc = RTCritSectLeave(&pThis->CritSect); + } - return VINF_SUCCESS; + return rc; } @@ -487,6 +592,9 @@ RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer) */ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession) { + AssertPtrReturn(phClientSession, VERR_INVALID_POINTER); + AssertReturn(hNmPipeSession != INVALID_HANDLE_VALUE, VERR_INVALID_HANDLE); + int rc; /* @@ -498,15 +606,18 @@ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE pThis->u32Magic = RTLOCALIPCSESSION_MAGIC; pThis->cRefs = 1; /* our ref */ pThis->fCancelled = false; + pThis->fIOPending = false; + pThis->fZeroByteRead = false; pThis->hNmPipe = hNmPipeSession; rc = RTCritSectInit(&pThis->CritSect); if (RT_SUCCESS(rc)) { - pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/); + pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, + FALSE /*bInitialState*/, NULL /*lpName*/); if (pThis->hEvent != NULL) { - memset(&pThis->OverlappedIO, 0, sizeof(pThis->OverlappedIO)); + RT_ZERO(pThis->OverlappedIO); pThis->OverlappedIO.Internal = STATUS_PENDING; pThis->OverlappedIO.hEvent = pThis->hEvent; @@ -528,10 +639,88 @@ static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE return rc; } - RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags) { - return VINF_SUCCESS; + AssertPtrReturn(phSession, VERR_INVALID_POINTER); + AssertPtrReturn(pszName, VERR_INVALID_POINTER); + AssertReturn(*pszName, VERR_INVALID_PARAMETER); + AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* Flags currently unused, must be 0. */ + + PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis)); + if (!pThis) + return VERR_NO_MEMORY; + + pThis->u32Magic = RTLOCALIPCSESSION_MAGIC; + pThis->cRefs = 1; /* The one we return. */ + pThis->fIOPending = false; + pThis->fZeroByteRead = false; + pThis->fCancelled = false; + pThis->pbBounceBuf = NULL; + pThis->cbBounceBufAlloc = 0; + pThis->cbBounceBufUsed = 0; + + int rc = RTCritSectInit(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, + FALSE /*bInitialState*/, NULL /*lpName*/); + if (pThis->hEvent != NULL) + { + RT_ZERO(pThis->OverlappedIO); + pThis->OverlappedIO.Internal = STATUS_PENDING; + pThis->OverlappedIO.hEvent = pThis->hEvent; + + PSECURITY_DESCRIPTOR pSecDesc; + rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, false /* Client */); + if (RT_SUCCESS(rc)) + { + char *pszPipe; + if (RTStrAPrintf(&pszPipe, "%s%s", RTLOCALIPC_WIN_PREFIX, pszName)) + { + SECURITY_ATTRIBUTES SecAttrs; + SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES); + SecAttrs.lpSecurityDescriptor = pSecDesc; + SecAttrs.bInheritHandle = FALSE; + + HANDLE hPipe = CreateFile(pszPipe, /* pipe name */ + GENERIC_READ /* read and write access */ + | GENERIC_WRITE, + 0, /* no sharing */ + &SecAttrs, /* lpSecurityAttributes */ + OPEN_EXISTING, /* opens existing pipe */ + FILE_FLAG_OVERLAPPED, /* default attributes */ + NULL); /* no template file */ + RTStrFree(pszPipe); + + if (hPipe != INVALID_HANDLE_VALUE) + { + LocalFree(pSecDesc); + + pThis->hNmPipe = hPipe; + *phSession = pThis; + return VINF_SUCCESS; + } + else + rc = RTErrConvertFromWin32(GetLastError()); + } + else + rc = VERR_NO_MEMORY; + + LocalFree(pSecDesc); + } + + BOOL fRc = CloseHandle(pThis->hEvent); + AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); + } + else + rc = RTErrConvertFromWin32(GetLastError()); + + int rc2 = RTCritSectDelete(&pThis->CritSect); + AssertRC(rc2); + } + + RTMemFree(pThis); + return rc; } @@ -564,9 +753,9 @@ RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession) */ if (hSession == NIL_RTLOCALIPCSESSION) return VINF_SUCCESS; - PRTLOCALIPCSESSIONINT pThis = (RTLOCALIPCSESSION)hSession; + PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic != RTLOCALIPCSESSION_MAGIC, VERR_INVALID_MAGIC); + AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_MAGIC); /* * Cancel any thread currently busy using the session, @@ -593,32 +782,437 @@ RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession) RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, size_t *pcbRead) { - return VINF_SUCCESS; + PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); + AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER); + /* pcbRead is optional. */ + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + /* No concurrent readers, sorry. */ + if (pThis->cRefs == 1) + { + pThis->cRefs++; + + /* + * If pcbRead is non-NULL this indicates the maximum number of bytes to read. + * If pcbRead is NULL then this is the exact number of bytes to read. + */ + size_t cbToRead = pcbRead ? *pcbRead : cbBuffer; + size_t cbTotalRead = 0; + while (cbToRead > 0) + { + /* + * Kick of a an overlapped read. It should return immediately if + * there is bytes in the buffer. If not, we'll cancel it and see + * what we get back. + */ + rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE); + DWORD cbRead = 0; + pThis->fIOPending = true; + RTCritSectLeave(&pThis->CritSect); + + if (ReadFile(pThis->hNmPipe, pvBuffer, + cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0, + &cbRead, &pThis->OverlappedIO)) + rc = VINF_SUCCESS; + else if (GetLastError() == ERROR_IO_PENDING) + { + WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE); + if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, + &cbRead, TRUE /*fWait*/)) + rc = VINF_SUCCESS; + else + { + DWORD dwErr = GetLastError(); + AssertMsgFailed(("err=%ld\n", dwErr)); + rc = RTErrConvertFromWin32(dwErr); + } + } + else + { + DWORD dwErr = GetLastError(); + AssertMsgFailed(("err2=%ld\n", dwErr)); + rc = RTErrConvertFromWin32(dwErr); + } + + RTCritSectEnter(&pThis->CritSect); + pThis->fIOPending = false; + if (RT_FAILURE(rc)) + break; + + /* Advance. */ + cbToRead -= cbRead; + cbTotalRead += cbRead; + pvBuffer = (uint8_t *)pvBuffer + cbRead; + } + + if (pcbRead) + { + *pcbRead = cbTotalRead; + if ( RT_FAILURE(rc) + && cbTotalRead + && rc != VERR_INVALID_POINTER) + rc = VINF_SUCCESS; + } + + pThis->cRefs--; + } + else + rc = VERR_WRONG_ORDER; + RTCritSectLeave(&pThis->CritSect); + } + + return rc; +} + + +/** + * Common worker for handling I/O completion. + * + * This is used by RTLocalIpcSessionClose and RTLocalIpcSessionWrite. + * + * @returns IPRT status code. + * @param pThis The pipe instance handle. + */ +static int rtLocalIpcSessionWriteCheckCompletion(PRTLOCALIPCSESSIONINT pThis) +{ + int rc; + DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0); + if (dwRc == WAIT_OBJECT_0) + { + DWORD cbWritten = 0; + if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE)) + { + for (;;) + { + if (cbWritten >= pThis->cbBounceBufUsed) + { + pThis->fIOPending = false; + rc = VINF_SUCCESS; + break; + } + + /* resubmit the remainder of the buffer - can this actually happen? */ + memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten); + rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE); + if (!WriteFile(pThis->hNmPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed, + &cbWritten, &pThis->OverlappedIO)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_IO_PENDING) + rc = VINF_TRY_AGAIN; + else + { + pThis->fIOPending = false; + if (dwErr == ERROR_NO_DATA) + rc = VERR_BROKEN_PIPE; + else + rc = RTErrConvertFromWin32(dwErr); + } + break; + } + Assert(cbWritten > 0); + } + } + else + { + pThis->fIOPending = false; + rc = RTErrConvertFromWin32(GetLastError()); + } + } + else if (dwRc == WAIT_TIMEOUT) + rc = VINF_TRY_AGAIN; + else + { + pThis->fIOPending = false; + if (dwRc == WAIT_ABANDONED) + rc = VERR_INVALID_HANDLE; + else + rc = RTErrConvertFromWin32(GetLastError()); + } + return rc; } RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer) { - return VINF_SUCCESS; + PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); + AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER); + AssertReturn(cbBuffer, VERR_INVALID_PARAMETER); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + /* No concurrent writers, sorry. */ + if (pThis->cRefs == 1) + { + pThis->cRefs++; + + /* + * If I/O is pending, wait for it to complete. + */ + if (pThis->fIOPending) + { + rc = rtLocalIpcSessionWriteCheckCompletion(pThis); + while (rc == VINF_TRY_AGAIN) + { + Assert(pThis->fIOPending); + HANDLE hEvent = pThis->OverlappedIO.hEvent; + RTCritSectLeave(&pThis->CritSect); + WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE); + RTCritSectEnter(&pThis->CritSect); + } + } + if (RT_SUCCESS(rc)) + { + Assert(!pThis->fIOPending); + + /* + * Try write everything. + * No bounce buffering, cUsers protects us. + */ + size_t cbTotalWritten = 0; + while (cbBuffer > 0) + { + BOOL fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE); + pThis->fIOPending = true; + RTCritSectLeave(&pThis->CritSect); + + DWORD cbWritten = 0; + fRc = WriteFile(pThis->hNmPipe, pvBuffer, + cbBuffer <= ~(DWORD)0 ? (DWORD)cbBuffer : ~(DWORD)0, + &cbWritten, &pThis->OverlappedIO); + if (fRc) + { + rc = VINF_SUCCESS; + } + else + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_IO_PENDING) + { + DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE); + if (dwRc == WAIT_OBJECT_0) + { + if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE /*fWait*/)) + rc = VINF_SUCCESS; + else + rc = RTErrConvertFromWin32(GetLastError()); + } + else if (dwRc == WAIT_TIMEOUT) + rc = VERR_TIMEOUT; + else if (dwRc == WAIT_ABANDONED) + rc = VERR_INVALID_HANDLE; + else + rc = RTErrConvertFromWin32(GetLastError()); + } + else if (dwErr == ERROR_NO_DATA) + rc = VERR_BROKEN_PIPE; + else + rc = RTErrConvertFromWin32(dwErr); + } + + RTCritSectEnter(&pThis->CritSect); + pThis->fIOPending = false; + if (RT_FAILURE(rc)) + break; + + /* Advance. */ + pvBuffer = (char const *)pvBuffer + cbWritten; + cbTotalWritten += cbWritten; + cbBuffer -= cbWritten; + } + } + + pThis->cRefs--; + } + else + rc = VERR_WRONG_ORDER; + RTCritSectLeave(&pThis->CritSect); + } + + return rc; } RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession) { + /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until + * all data was written (or an error occurred). */ + /** @todo Implement this as soon as we want an explicit asynchronous version of + * RTLocalIpcSessionWrite on Windows. */ return VINF_SUCCESS; } RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies) { - RTThreadSleep(1000); - return VINF_SUCCESS; + PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); + + uint64_t const StartMsTS = RTTimeMilliTS(); + + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_FAILURE(rc)) + return rc; + for (unsigned iLoop = 0;; iLoop++) + { + HANDLE hWait = INVALID_HANDLE_VALUE; + + if (pThis->fIOPending) + hWait = pThis->OverlappedIO.hEvent; + else + { + /* Peek at the pipe buffer and see how many bytes it contains. */ + DWORD cbAvailable; + BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL); + if ( fRc + && cbAvailable) + { + rc = VINF_SUCCESS; + break; + } + else if (!fRc) + { + rc = RTErrConvertFromWin32(GetLastError()); + break; + } + + /* Start a zero byte read operation that we can wait on. */ + if (cMillies == 0) + { + rc = VERR_TIMEOUT; + break; + } + AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER); + fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE); + DWORD cbRead = 0; + if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO)) + { + rc = VINF_SUCCESS; + if (iLoop > 10) + RTThreadYield(); + } + else if (GetLastError() == ERROR_IO_PENDING) + { + pThis->cRefs++; + pThis->fIOPending = true; + pThis->fZeroByteRead = true; + hWait = pThis->OverlappedIO.hEvent; + } + else + rc = RTErrConvertFromWin32(GetLastError()); + } + + if (RT_FAILURE(rc)) + break; + + /* + * Check for timeout. + */ + DWORD cMsMaxWait = INFINITE; + if ( cMillies != RT_INDEFINITE_WAIT + && ( hWait != INVALID_HANDLE_VALUE + || iLoop > 10) + ) + { + uint64_t cElapsed = RTTimeMilliTS() - StartMsTS; + if (cElapsed >= cMillies) + { + rc = VERR_TIMEOUT; + break; + } + cMsMaxWait = cMillies - (uint32_t)cElapsed; + } + + /* + * Wait. + */ + if (hWait != INVALID_HANDLE_VALUE) + { + RTCritSectLeave(&pThis->CritSect); + + DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait); + if (dwRc == WAIT_OBJECT_0) + rc = VINF_SUCCESS; + else if (dwRc == WAIT_TIMEOUT) + rc = VERR_TIMEOUT; + else if (dwRc == WAIT_ABANDONED) + rc = VERR_INVALID_HANDLE; + else + rc = RTErrConvertFromWin32(GetLastError()); + + if ( RT_FAILURE(rc) + && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC) + return rc; + + int rc2 = RTCritSectEnter(&pThis->CritSect); + AssertRC(rc2); + if (pThis->fZeroByteRead) + { + Assert(pThis->cRefs); + pThis->cRefs--; + pThis->fIOPending = false; + + if (rc != VINF_SUCCESS) + { + BOOL fRc = CancelIo(pThis->hNmPipe); + Assert(fRc == TRUE); + } + + DWORD cbRead = 0; + BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/); + if ( !fRc + && RT_SUCCESS(rc)) + { + DWORD dwRc = GetLastError(); + if (dwRc == ERROR_OPERATION_ABORTED) + rc = VERR_CANCELLED; + else + rc = RTErrConvertFromWin32(dwRc); + } + } + + if (RT_FAILURE(rc)) + break; + } + } + + int rc2 = RTCritSectLeave(&pThis->CritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + + return rc; } RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession) { - return VINF_SUCCESS; + PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); + + /* + * Enter the critical section, then set the cancellation flag + * and signal the event (to wake up anyone in/at WaitForSingleObject). + */ + int rc = RTCritSectEnter(&pThis->CritSect); + if (RT_SUCCESS(rc)) + { + ASMAtomicUoWriteBool(&pThis->fCancelled, true); + BOOL fRc = SetEvent(pThis->hEvent); + AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); + + RTCritSectLeave(&pThis->CritSect); + } + + return rc; } diff --git a/src/VBox/Runtime/r3/win/mp-win.cpp b/src/VBox/Runtime/r3/win/mp-win.cpp index fed1152b..dce41d19 100644 --- a/src/VBox/Runtime/r3/win/mp-win.cpp +++ b/src/VBox/Runtime/r3/win/mp-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,9 +30,14 @@ *******************************************************************************/ #define LOG_GROUP RTLOGGROUP_SYSTEM #include <Windows.h> + #include <iprt/mp.h> -#include <iprt/cpuset.h> +#include "internal/iprt.h" + #include <iprt/assert.h> +#include <iprt/cpuset.h> +#include <iprt/ldr.h> +#include <iprt/mem.h> AssertCompile(MAXIMUM_PROCESSORS <= RTCPUSET_MAX_CPUS); @@ -91,6 +96,59 @@ RTDECL(RTCPUID) RTMpGetCount(void) } +RTDECL(RTCPUID) RTMpGetCoreCount(void) +{ + /* + * Resolve the API dynamically (one try) as it requires XP w/ sp3 or later. + */ + typedef BOOL (WINAPI *PFNGETLOGICALPROCINFO)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + static PFNGETLOGICALPROCINFO s_pfnGetLogicalProcInfo = (PFNGETLOGICALPROCINFO)~(uintptr_t)0; + if (s_pfnGetLogicalProcInfo == (PFNGETLOGICALPROCINFO)~(uintptr_t)0) + s_pfnGetLogicalProcInfo = (PFNGETLOGICALPROCINFO)RTLdrGetSystemSymbol("kernel32.dll", "GetLogicalProcessorInformation"); + + if (s_pfnGetLogicalProcInfo) + { + /* + * Query the information. This unfortunately requires a buffer, so we + * start with a guess and let windows advice us if it's too small. + */ + DWORD cbSysProcInfo = _4K; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION paSysInfo = NULL; + BOOL fRc = FALSE; + do + { + cbSysProcInfo = RT_ALIGN_32(cbSysProcInfo, 256); + void *pv = RTMemRealloc(paSysInfo, cbSysProcInfo); + if (!pv) + break; + paSysInfo = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)pv; + fRc = s_pfnGetLogicalProcInfo(paSysInfo, &cbSysProcInfo); + } while (!fRc && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + if (fRc) + { + /* + * Parse the result. + */ + uint32_t cCores = 0; + uint32_t i = cbSysProcInfo / sizeof(paSysInfo[0]); + while (i-- > 0) + if (paSysInfo[i].Relationship == RelationProcessorCore) + cCores++; + + RTMemFree(paSysInfo); + Assert(cCores > 0); + return cCores; + } + + RTMemFree(paSysInfo); + } + + /* If we don't have the necessary API or if it failed, return the same + value as the generic implementation. */ + return RTMpGetCount(); +} + + RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { SYSTEM_INFO SysInfo; @@ -107,3 +165,10 @@ RTDECL(RTCPUID) RTMpGetOnlineCount(void) return RTCpuSetCount(&Set); } + +RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void) +{ + /** @todo this isn't entirely correct. */ + return RTMpGetCoreCount(); +} + diff --git a/src/VBox/Runtime/r3/win/ntdll-mini-implib.c b/src/VBox/Runtime/r3/win/ntdll-mini-implib.c index 74094221..a3eeef7b 100644 --- a/src/VBox/Runtime/r3/win/ntdll-mini-implib.c +++ b/src/VBox/Runtime/r3/win/ntdll-mini-implib.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -34,13 +34,23 @@ typedef LONG NTSTATUS; typedef PVOID PIO_STATUS_BLOCK; typedef INT FILE_INFORMATION_CLASS; typedef INT FS_INFORMATION_CLASS; +typedef INT MEMORY_INFORMATION_CLASS; +typedef INT PROCESSINFOCLASS; +typedef PVOID POBJECT_ATTRIBUTES; +typedef PVOID PIO_APC_ROUTINE; +typedef PVOID PUNICODE_STRING; +/* Error/status conversion: */ + NTSYSAPI ULONG NTAPI RtlNtStatusToDosError(IN NTSTATUS Status) { return 1; } + +/* Queries: */ + NTSYSAPI LONG NTAPI NtQueryTimerResolution(OUT PULONG MaximumResolution, OUT PULONG MinimumResolution, OUT PULONG CurrentResolution) @@ -48,15 +58,72 @@ NTSYSAPI LONG NTAPI NtQueryTimerResolution(OUT PULONG MaximumResolution, return -1; } -NTSYSAPI NTSTATUS WINAPI NtQueryInformationFile(HANDLE h, - PIO_STATUS_BLOCK b, - PVOID c, - LONG d, - FILE_INFORMATION_CLASS e) +NTSYSAPI LONG NTAPI NtQueryDirectoryFile(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan) +{ + return -1; +} + +NTSYSAPI LONG NTAPI NtQueryDirectoryObject(IN HANDLE ObjectHandle, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturneLength) +{ + return -1; +} + +NTSYSAPI NTSTATUS WINAPI NtQueryInformationFile(IN HANDLE h, + OUT PIO_STATUS_BLOCK b, + OUT PVOID pvBuf, + IN LONG cbBuf, + IN FILE_INFORMATION_CLASS e) +{ + return -1; +} + +NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess(IN HANDLE hProcess, + IN PROCESSINFOCLASS enmProcInfo, + OUT PVOID pvBuf, + IN SIZE_T cbBuf, + OUT PSIZE_T pcbReturned OPTIONAL) +{ + return -1; +} + +NTSYSAPI NTSTATUS NTAPI NtQueryVolumeInformationFile(IN HANDLE hFile, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID pvBuf, + IN ULONG cbBuf, + IN FS_INFORMATION_CLASS FsInformationClass) +{ + return -1; +} + +NTSYSAPI NTSTATUS NTAPI NtQueryVirtualMemory(IN HANDLE hProcess, + IN LPCVOID pvWhere, + IN MEMORY_INFORMATION_CLASS MemoryInfo, + OUT PVOID pvBuf, + IN SIZE_T cbBuf, + OUT PSIZE_T pcbReturned OPTIONAL) { return -1; } + +/* Setters: */ + NTSYSAPI NTSTATUS NTAPI NtSetInformationFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, @@ -73,11 +140,33 @@ NTSYSAPI LONG NTAPI NtSetTimerResolution(IN ULONG DesiredResolution, return -1; } -NTSYSAPI NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE h, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID pvBuf, - ULONG cbBuf, - FS_INFORMATION_CLASS FsInformationClass) + + +/* Handles: */ + +NTSYSAPI NTSTATUS NTAPI NtCreateFile(OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer, + IN ULONG EaLength) +{ + return -1; +} + +NTSYSAPI NTSTATUS NTAPI NtOpenDirectoryObject(OUT PHANDLE ObjectHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -1; +} + +NTSYSAPI NTSTATUS NTAPI NtClose(IN HANDLE Handle) { return -1; } diff --git a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def index a0d39ee4..64bc9328 100644 --- a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def +++ b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def @@ -4,7 +4,7 @@ ; ; -; Copyright (C) 2010 Oracle Corporation +; Copyright (C) 2010-2013 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; @@ -28,8 +28,13 @@ LIBRARY ntdll.dll EXPORTS RtlNtStatusToDosError NtQueryTimerResolution + NtQueryDirectoryFile NtQueryInformationFile + NtQueryInformationProcess NtSetInformationFile NtSetTimerResolution NtQueryVolumeInformationFile - + NtQueryVirtualMemory + NtCreateFile + NtClose + NtOpenDirectoryObject diff --git a/src/VBox/Runtime/r3/win/path-win.cpp b/src/VBox/Runtime/r3/win/path-win.cpp index aacf7d5f..0245b778 100644 --- a/src/VBox/Runtime/r3/win/path-win.cpp +++ b/src/VBox/Runtime/r3/win/path-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -195,7 +195,7 @@ RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath) AssertReturn(cchPath, VERR_INVALID_PARAMETER); RTLDRMOD hShell32; - int rc = RTLdrLoad("Shell32.dll", &hShell32); + int rc = RTLdrLoadSystem("Shell32.dll", true /*fNoUnload*/, &hShell32); if (RT_SUCCESS(rc)) { PFNSHGETFOLDERPATHW pfnSHGetFolderPathW; diff --git a/src/VBox/Runtime/r3/win/pipe-win.cpp b/src/VBox/Runtime/r3/win/pipe-win.cpp index 5abe809e..11f8b432 100644 --- a/src/VBox/Runtime/r3/win/pipe-win.cpp +++ b/src/VBox/Runtime/r3/win/pipe-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -724,7 +724,7 @@ RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_ int rc = RTCritSectEnter(&pThis->CritSect); if (RT_SUCCESS(rc)) { - /* No concurrent readers, sorry. */ + /* No concurrent writers, sorry. */ if (pThis->cUsers == 0) { pThis->cUsers++; @@ -839,7 +839,7 @@ RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrit int rc = RTCritSectEnter(&pThis->CritSect); if (RT_SUCCESS(rc)) { - /* No concurrent readers, sorry. */ + /* No concurrent writers, sorry. */ if (pThis->cUsers == 0) { pThis->cUsers++; @@ -1170,28 +1170,19 @@ RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable) } -/** - * Internal RTPollSetAdd helper that returns the handle that should be added to - * the pollset. - * - * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure. - * @param hPipe The pipe handle. - * @param fEvents The events we're polling for. - * @param ph where to put the primary handle. - */ -int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PHANDLE ph) +int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative) { RTPIPEINTERNAL *pThis = hPipe; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER); + AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER); AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER); /* Later: Try register an event handle with the pipe like on OS/2, there is a file control for doing this obviously intended for the OS/2 subsys. The question is whether this still exists on Vista and W7. */ - *ph = pThis->Overlapped.hEvent; + *phNative = (RTHCINTPTR)pThis->Overlapped.hEvent; return VINF_SUCCESS; } @@ -1397,6 +1388,7 @@ uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool f /* update counters. */ pThis->cUsers--; + /** @todo This isn't sane, or is it? See OS/2 impl. */ if (!pThis->cUsers) pThis->hPollSet = NIL_RTPOLLSET; diff --git a/src/VBox/Runtime/r3/win/poll-win.cpp b/src/VBox/Runtime/r3/win/poll-win.cpp deleted file mode 100644 index 0f3b187f..00000000 --- a/src/VBox/Runtime/r3/win/poll-win.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/* $Id: poll-win.cpp $ */ -/** @file - * IPRT - Polling I/O Handles, Windows Implementation. - * - * @todo merge poll-win.cpp and poll-posix.cpp, there is lots of common code. - */ - -/* - * Copyright (C) 2010 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * - * The contents of this file may alternatively be used under the terms - * of the Common Development and Distribution License Version 1.0 - * (CDDL) only, as it comes in the "COPYING.CDDL" file of the - * VirtualBox OSE distribution, in which case the provisions of the - * CDDL are applicable instead of those of the GPL. - * - * You may elect to license modified versions of this file under the - * terms and conditions of either the GPL or the CDDL or both. - */ - - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#include <Windows.h> - -#include <iprt/poll.h> -#include "internal/iprt.h" - -#include <iprt/asm.h> -#include <iprt/assert.h> -#include <iprt/err.h> -#include <iprt/mem.h> -#include <iprt/pipe.h> -#include <iprt/string.h> -#include <iprt/thread.h> -#include <iprt/time.h> - -#include "internal/pipe.h" -#define IPRT_INTERNAL_SOCKET_POLLING_ONLY -#include "internal/socket.h" -#include "internal/magics.h" - - -/******************************************************************************* -* Structures and Typedefs * -*******************************************************************************/ -/** - * Handle entry in a poll set. - */ -typedef struct RTPOLLSETHNDENT -{ - /** The handle type. */ - RTHANDLETYPE enmType; - /** The handle ID. */ - uint32_t id; - /** The events we're waiting for here. */ - uint32_t fEvents; - /** Set if this is the final entry for this handle. - * If the handle is entered more than once, this will be clear for all but - * the last entry. */ - bool fFinalEntry; - /** The handle union. */ - RTHANDLEUNION u; -} RTPOLLSETHNDENT; -/** Pointer to a handle entry. */ -typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT; - - -/** - * Poll set data, Windows. - */ -typedef struct RTPOLLSETINTERNAL -{ - /** The magic value (RTPOLLSET_MAGIC). */ - uint32_t u32Magic; - /** Set when someone is polling or making changes. */ - bool volatile fBusy; - - /** The number of valid handles in the set. */ - uint32_t cHandles; - /** The native handles. */ - HANDLE ahNative[MAXIMUM_WAIT_OBJECTS]; - /** Array of handles and IDs. */ - RTPOLLSETHNDENT aHandles[MAXIMUM_WAIT_OBJECTS]; -} RTPOLLSETINTERNAL; - - -/** - * Common worker for RTPoll and RTPollNoResume - */ -static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - int rc; - - if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT)) - return VERR_DEADLOCK; - - /* - * Check for special case, RTThreadSleep... - */ - uint32_t const cHandles = pThis->cHandles; - if (cHandles == 0) - { - rc = RTThreadSleep(cMillies); - if (RT_SUCCESS(rc)) - rc = VERR_TIMEOUT; - return rc; - } - - /* - * Check + prepare the handles before waiting. - */ - uint32_t fEvents = 0; - bool const fNoWait = cMillies == 0; - uint32_t i; - for (i = 0; i < cHandles; i++) - { - switch (pThis->aHandles[i].enmType) - { - case RTHANDLETYPE_PIPE: - fEvents = rtPipePollStart(pThis->aHandles[i].u.hPipe, pThis, pThis->aHandles[i].fEvents, - pThis->aHandles[i].fFinalEntry, fNoWait); - break; - - case RTHANDLETYPE_SOCKET: - fEvents = rtSocketPollStart(pThis->aHandles[i].u.hSocket, pThis, pThis->aHandles[i].fEvents, - pThis->aHandles[i].fFinalEntry, fNoWait); - break; - - default: - AssertFailed(); - fEvents = UINT32_MAX; - break; - } - if (fEvents) - break; - } - if ( fEvents - || fNoWait) - { - - if (pid) - *pid = pThis->aHandles[i].id; - if (pfEvents) - *pfEvents = fEvents; - rc = !fEvents - ? VERR_TIMEOUT - : fEvents != UINT32_MAX - ? VINF_SUCCESS - : VERR_INTERNAL_ERROR_4; - - /* clean up */ - if (!fNoWait) - while (i-- > 0) - { - switch (pThis->aHandles[i].enmType) - { - case RTHANDLETYPE_PIPE: - rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents, - pThis->aHandles[i].fFinalEntry, false); - break; - - case RTHANDLETYPE_SOCKET: - rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents, - pThis->aHandles[i].fFinalEntry, false); - break; - - default: - AssertFailed(); - break; - } - } - - return rc; - } - - /* - * Wait. - */ - DWORD dwRc = WaitForMultipleObjectsEx(cHandles, &pThis->ahNative[0], - FALSE /*fWaitAll */, - cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies, - TRUE /*fAlertable*/); - if ( dwRc >= WAIT_OBJECT_0 - && dwRc < WAIT_OBJECT_0 + cHandles) - rc = VERR_INTERRUPTED; - else if (dwRc == WAIT_TIMEOUT) - rc = VERR_TIMEOUT; - else if (dwRc == WAIT_IO_COMPLETION) - rc = VERR_INTERRUPTED; - else if (dwRc == WAIT_FAILED) - rc = RTErrConvertFromWin32(GetLastError()); - else - { - AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc)); - rc = VERR_INTERNAL_ERROR_5; - } - - /* - * Get event (if pending) and do wait cleanup. - */ - bool fHarvestEvents = true; - for (i = 0; i < cHandles; i++) - { - fEvents = 0; - switch (pThis->aHandles[i].enmType) - { - case RTHANDLETYPE_PIPE: - fEvents = rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents, - pThis->aHandles[i].fFinalEntry, fHarvestEvents); - break; - - case RTHANDLETYPE_SOCKET: - fEvents = rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents, - pThis->aHandles[i].fFinalEntry, fHarvestEvents); - break; - - default: - AssertFailed(); - break; - } - if ( fEvents - && fHarvestEvents) - { - Assert(fEvents != UINT32_MAX); - fHarvestEvents = false; - if (pfEvents) - *pfEvents = fEvents; - if (pid) - *pid = pThis->aHandles[i].id; - rc = VINF_SUCCESS; - } - } - - return rc; -} - - -RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertPtrNull(pfEvents); - AssertPtrNull(pid); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc; - if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0) - { - do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - while (rc == VERR_INTERRUPTED); - } - else - { - uint64_t MsStart = RTTimeMilliTS(); - rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - while (RT_UNLIKELY(rc == VERR_INTERRUPTED)) - { - if (RTTimeMilliTS() - MsStart >= cMillies) - { - rc = VERR_TIMEOUT; - break; - } - rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - } - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - - return rc; -} - - -RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) -{ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertPtrNull(pfEvents); - AssertPtrNull(pid); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); - - ASMAtomicWriteBool(&pThis->fBusy, false); - - return rc; -} - - -RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet) -{ - AssertPtrReturn(phPollSet, VERR_INVALID_POINTER); - RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAllocZ(sizeof(RTPOLLSETINTERNAL)); - if (!pThis) - return VERR_NO_MEMORY; - - pThis->u32Magic = RTPOLLSET_MAGIC; - pThis->fBusy = false; - pThis->cHandles = 0; - for (size_t i = 0; i < RT_ELEMENTS(pThis->ahNative); i++) - pThis->ahNative[i] = INVALID_HANDLE_VALUE; - - *phPollSet = pThis; - return VINF_SUCCESS; -} - - -RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet) -{ - RTPOLLSETINTERNAL *pThis = hPollSet; - if (pThis == NIL_RTPOLLSET) - return VINF_SUCCESS; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC); - RTMemFree(pThis); - - return VINF_SUCCESS; -} - - -RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id) -{ - /* - * Validate the input (tedious). - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); - AssertReturn(fEvents, VERR_INVALID_PARAMETER); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - - if (!pHandle) - return VINF_SUCCESS; - AssertPtrReturn(pHandle, VERR_INVALID_POINTER); - AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VINF_SUCCESS; - HANDLE hNative = INVALID_HANDLE_VALUE; - RTHANDLEUNION uh; - uh.uInt = 0; - switch (pHandle->enmType) - { - case RTHANDLETYPE_PIPE: - uh.hPipe = pHandle->u.hPipe; - if (uh.hPipe != NIL_RTPIPE) - rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative); - break; - - case RTHANDLETYPE_SOCKET: - uh.hSocket = pHandle->u.hSocket; - if (uh.hSocket != NIL_RTSOCKET) - rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative); - break; - - case RTHANDLETYPE_FILE: - AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n")); - rc = VERR_POLL_HANDLE_NOT_POLLABLE; - break; - - case RTHANDLETYPE_THREAD: - AssertMsgFailed(("Thread handles are currently not pollable\n")); - rc = VERR_POLL_HANDLE_NOT_POLLABLE; - break; - - default: - AssertMsgFailed(("\n")); - rc = VERR_POLL_HANDLE_NOT_POLLABLE; - break; - } - if ( RT_SUCCESS(rc) - && hNative != INVALID_HANDLE_VALUE) - { - uint32_t const i = pThis->cHandles; - - /* Check that the handle ID doesn't exist already. */ - uint32_t iPrev = UINT32_MAX; - uint32_t j = i; - while (j-- > 0) - { - if (pThis->aHandles[j].id == id) - { - rc = VERR_POLL_HANDLE_ID_EXISTS; - break; - } - if ( pThis->aHandles[j].enmType == pHandle->enmType - && pThis->aHandles[j].u.uInt == uh.uInt) - iPrev = j; - } - - /* Check that we won't overflow the poll set now. */ - if ( RT_SUCCESS(rc) - && i + 1 > RT_ELEMENTS(pThis->ahNative)) - rc = VERR_POLL_SET_IS_FULL; - if (RT_SUCCESS(rc)) - { - /* Add the handles to the two parallel arrays. */ - pThis->ahNative[i] = hNative; - pThis->aHandles[i].enmType = pHandle->enmType; - pThis->aHandles[i].u = uh; - pThis->aHandles[i].id = id; - pThis->aHandles[i].fEvents = fEvents; - pThis->aHandles[i].fFinalEntry = true; - pThis->cHandles = i + 1; - - if (iPrev != UINT32_MAX) - { - Assert(pThis->aHandles[i].fFinalEntry); - pThis->aHandles[i].fFinalEntry = false; - } - - rc = VINF_SUCCESS; - } - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - - -RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; - uint32_t i = pThis->cHandles; - while (i-- > 0) - if (pThis->aHandles[i].id == id) - { - /* Save some details for the duplicate searching. */ - bool fFinalEntry = pThis->aHandles[i].fFinalEntry; - RTHANDLETYPE enmType = pThis->aHandles[i].enmType; - RTHANDLEUNION uh = pThis->aHandles[i].u; - - /* Remove the entry. */ - pThis->cHandles--; - size_t const cToMove = pThis->cHandles - i; - if (cToMove) - { - memmove(&pThis->aHandles[i], &pThis->aHandles[i + 1], cToMove * sizeof(pThis->aHandles[i])); - memmove(&pThis->ahNative[i], &pThis->ahNative[i + 1], cToMove * sizeof(pThis->ahNative[i])); - } - - /* Check for duplicate and set the fFinalEntry flag. */ - if (fFinalEntry) - while (i-- > 0) - if ( pThis->aHandles[i].u.uInt == uh.uInt - && pThis->aHandles[i].enmType == enmType) - { - Assert(!pThis->aHandles[i].fFinalEntry); - pThis->aHandles[i].fFinalEntry = true; - break; - } - - rc = VINF_SUCCESS; - break; - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - - -RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; - uint32_t i = pThis->cHandles; - while (i-- > 0) - if (pThis->aHandles[i].id == id) - { - if (pHandle) - { - pHandle->enmType = pThis->aHandles[i].enmType; - pHandle->u = pThis->aHandles[i].u; - } - rc = VINF_SUCCESS; - break; - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - - -RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, UINT32_MAX); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX); - uint32_t cHandles = pThis->cHandles; - ASMAtomicWriteBool(&pThis->fBusy, false); - - return cHandles; -} - -RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents) -{ - /* - * Validate the input. - */ - RTPOLLSETINTERNAL *pThis = hPollSet; - AssertPtrReturn(pThis, VERR_INVALID_HANDLE); - AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); - AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); - AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); - AssertReturn(fEvents, VERR_INVALID_PARAMETER); - - /* - * Set the busy flag and do the job. - */ - AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); - - int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; - uint32_t i = pThis->cHandles; - while (i-- > 0) - if (pThis->aHandles[i].id == id) - { - pThis->aHandles[i].fEvents = fEvents; - rc = VINF_SUCCESS; - break; - } - - ASMAtomicWriteBool(&pThis->fBusy, false); - return rc; -} - diff --git a/src/VBox/Runtime/r3/win/process-win.cpp b/src/VBox/Runtime/r3/win/process-win.cpp index 47f6d9eb..41a8cbf8 100644 --- a/src/VBox/Runtime/r3/win/process-win.cpp +++ b/src/VBox/Runtime/r3/win/process-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -40,7 +40,7 @@ #include <Lmcons.h> #include <iprt/process.h> -#include "internal/iprt.h" +#include "internal-r3-win.h" #include <iprt/assert.h> #include <iprt/critsect.h> @@ -50,6 +50,7 @@ #include <iprt/getopt.h> #include <iprt/initterm.h> #include <iprt/ldr.h> +#include <iprt/log.h> #include <iprt/mem.h> #include <iprt/once.h> #include <iprt/path.h> @@ -58,6 +59,7 @@ #include <iprt/socket.h> + /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ @@ -157,12 +159,11 @@ static DECLCALLBACK(void) rtProcWinTerm(RTTERMREASON enmReason, int32_t iStatus, * Initialize the globals. * * @returns IPRT status code. - * @param pvUser1 Ignored. - * @param pvUser2 Ignored. + * @param pvUser Ignored. */ -static DECLCALLBACK(int32_t) rtProcWinInitOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int32_t) rtProcWinInitOnce(void *pvUser) { - NOREF(pvUser1); NOREF(pvUser2); + NOREF(pvUser); g_cProcesses = 0; g_cProcessesAlloc = 0; @@ -294,7 +295,8 @@ static int rtProcWinMapErrorCodes(DWORD dwError) case ERROR_PASSWORD_EXPIRED: case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */ case ERROR_PASSWORD_RESTRICTION: - rc = VERR_AUTHENTICATION_FAILURE; + case ERROR_ACCOUNT_DISABLED: /* See: http://support.microsoft.com/kb/263936 */ + rc = VERR_ACCOUNT_RESTRICTED; break; case ERROR_FILE_CORRUPT: @@ -420,77 +422,73 @@ static bool rtProcWinFindTokenByProcessAndPsApi(const char * const *papszNames, /* * Load PSAPI.DLL and resolve the two symbols we need. */ - RTLDRMOD hPsApi; - int rc = RTLdrLoad("PSAPI.dll", &hPsApi); - if (RT_FAILURE_NP(rc)) + PFNGETMODULEBASENAME pfnGetModuleBaseName = (PFNGETMODULEBASENAME)RTLdrGetSystemSymbol("psapi.dll", "GetModuleBaseName"); + if (!pfnGetModuleBaseName) return false; - PFNGETMODULEBASENAME pfnGetModuleBaseName; - PFNENUMPROCESSES pfnEnumProcesses; - rc = RTLdrGetSymbol(hPsApi, "EnumProcesses", (void**)&pfnEnumProcesses); - if (RT_SUCCESS(rc)) - rc = RTLdrGetSymbol(hPsApi, "GetModuleBaseName", (void**)&pfnGetModuleBaseName); + PFNENUMPROCESSES pfnEnumProcesses = (PFNENUMPROCESSES)RTLdrGetSystemSymbol("psapi.dll", "EnumProcesses"); + if (!pfnEnumProcesses) + return false; + + /* + * Get a list of PID. We retry if it looks like there are more PIDs + * to be returned than what we supplied buffer space for. + */ + int rc = VINF_SUCCESS; + DWORD cbPidsAllocated = 4096; + DWORD cbPidsReturned = 0; + DWORD *paPids; + for (;;) + { + paPids = (DWORD *)RTMemTmpAlloc(cbPidsAllocated); + AssertBreakStmt(paPids, rc = VERR_NO_TMP_MEMORY); + if (!pfnEnumProcesses(paPids, cbPidsAllocated, &cbPidsReturned)) + { + rc = RTErrConvertFromWin32(GetLastError()); + AssertMsgFailedBreak(("%Rrc\n", rc)); + } + if ( cbPidsReturned < cbPidsAllocated + || cbPidsAllocated >= _512K) + break; + RTMemTmpFree(paPids); + cbPidsAllocated *= 2; + } if (RT_SUCCESS(rc)) { /* - * Get a list of PID. We retry if it looks like there are more PIDs - * to be returned than what we supplied buffer space for. + * Search for the process. + * + * We ASSUME that the caller won't be specifying any names longer + * than RTPATH_MAX. */ - DWORD cbPidsAllocated = 4096; - DWORD cbPidsReturned = 0; - DWORD *paPids; - for (;;) - { - paPids = (DWORD *)RTMemTmpAlloc(cbPidsAllocated); - AssertBreakStmt(paPids, rc = VERR_NO_TMP_MEMORY); - if (!pfnEnumProcesses(paPids, cbPidsAllocated, &cbPidsReturned)) - { - rc = RTErrConvertFromWin32(GetLastError()); - AssertMsgFailedBreak(("%Rrc\n", rc)); - } - if ( cbPidsReturned < cbPidsAllocated - || cbPidsAllocated >= _512K) - break; - RTMemTmpFree(paPids); - cbPidsAllocated *= 2; - } - if (RT_SUCCESS(rc)) + DWORD cbProcName = RTPATH_MAX; + char *pszProcName = (char *)RTMemTmpAlloc(RTPATH_MAX); + if (pszProcName) { - /* - * Search for the process. - * - * We ASSUME that the caller won't be specifying any names longer - * than RTPATH_MAX. - */ - DWORD cbProcName = RTPATH_MAX; - char *pszProcName = (char *)RTMemTmpAlloc(RTPATH_MAX); - if (pszProcName) + for (size_t i = 0; papszNames[i] && !fFound; i++) { - for (size_t i = 0; papszNames[i] && !fFound; i++) + const DWORD cPids = cbPidsReturned / sizeof(DWORD); + for (DWORD iPid = 0; iPid < cPids && !fFound; iPid++) { - const DWORD cPids = cbPidsReturned / sizeof(DWORD); - for (DWORD iPid = 0; iPid < cPids && !fFound; iPid++) + HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, paPids[iPid]); + if (hProc) { - HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, paPids[iPid]); - if (hProc) - { - *pszProcName = '\0'; - DWORD cbRet = pfnGetModuleBaseName(hProc, 0 /*hModule = exe */, pszProcName, cbProcName); - if ( cbRet > 0 - && _stricmp(pszProcName, papszNames[i]) == 0 - && RT_SUCCESS(rtProcWinGetProcessTokenHandle(paPids[iPid], pSid, phToken))) - fFound = true; - CloseHandle(hProc); - } + *pszProcName = '\0'; + DWORD cbRet = pfnGetModuleBaseName(hProc, 0 /*hModule = exe */, pszProcName, cbProcName); + if ( cbRet > 0 + && _stricmp(pszProcName, papszNames[i]) == 0 + && RT_SUCCESS(rtProcWinGetProcessTokenHandle(paPids[iPid], pSid, phToken))) + fFound = true; + CloseHandle(hProc); } } - RTMemTmpFree(pszProcName); } - else - rc = VERR_NO_TMP_MEMORY; + RTMemTmpFree(pszProcName); } - RTMemTmpFree(paPids); + else + rc = VERR_NO_TMP_MEMORY; } - RTLdrClose(hPsApi); + RTMemTmpFree(paPids); + return fFound; } @@ -517,59 +515,48 @@ static bool rtProcWinFindTokenByProcess(const char * const *papszNames, PSID pSi * On modern systems (W2K+) try the Toolhelp32 API first; this is more stable * and reliable. Fallback to EnumProcess on NT4. */ - RTLDRMOD hKernel32; - int rc = RTLdrLoad("Kernel32.dll", &hKernel32); - if (RT_SUCCESS(rc)) + PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot; + pfnCreateToolhelp32Snapshot = (PFNCREATETOOLHELP32SNAPSHOT)GetProcAddress(g_hModKernel32, "CreateToolhelp32Snapshot"); + PFNPROCESS32FIRST pfnProcess32First = (PFNPROCESS32FIRST)GetProcAddress(g_hModKernel32, "Process32First"); + PFNPROCESS32NEXT pfnProcess32Next = (PFNPROCESS32NEXT )GetProcAddress(g_hModKernel32, "Process32Next"); + bool fFallback = true; + if (pfnProcess32Next && pfnProcess32First && pfnCreateToolhelp32Snapshot) { - PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot; - PFNPROCESS32FIRST pfnProcess32First; - PFNPROCESS32NEXT pfnProcess32Next; - rc = RTLdrGetSymbol(hKernel32, "CreateToolhelp32Snapshot", (void **)&pfnCreateToolhelp32Snapshot); - if (RT_SUCCESS(rc)) - rc = RTLdrGetSymbol(hKernel32, "Process32First", (void**)&pfnProcess32First); - if (RT_SUCCESS(rc)) - rc = RTLdrGetSymbol(hKernel32, "Process32Next", (void**)&pfnProcess32Next); - - if (RT_SUCCESS(rc)) + HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap != INVALID_HANDLE_VALUE) { - HANDLE hSnap = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (hSnap != INVALID_HANDLE_VALUE) + fFallback = false; + for (size_t i = 0; papszNames[i] && !fFound; i++) { - for (size_t i = 0; papszNames[i] && !fFound; i++) + PROCESSENTRY32 procEntry; + procEntry.dwSize = sizeof(PROCESSENTRY32); + if (pfnProcess32First(hSnap, &procEntry)) { - PROCESSENTRY32 procEntry; - procEntry.dwSize = sizeof(PROCESSENTRY32); - if (pfnProcess32First(hSnap, &procEntry)) + do { - do + if ( _stricmp(procEntry.szExeFile, papszNames[i]) == 0 + && RT_SUCCESS(rtProcWinGetProcessTokenHandle(procEntry.th32ProcessID, pSid, phToken))) { - if ( _stricmp(procEntry.szExeFile, papszNames[i]) == 0 - && RT_SUCCESS(rtProcWinGetProcessTokenHandle(procEntry.th32ProcessID, pSid, phToken))) - { - fFound = true; - break; - } - } while (pfnProcess32Next(hSnap, &procEntry)); - } + fFound = true; + break; + } + } while (pfnProcess32Next(hSnap, &procEntry)); + } #ifdef RT_STRICT - else - { - DWORD dwErr = GetLastError(); - AssertMsgFailed(("dwErr=%u (%x)\n", dwErr, dwErr)); - } -#endif + else + { + DWORD dwErr = GetLastError(); + AssertMsgFailed(("dwErr=%u (%x)\n", dwErr, dwErr)); } - CloseHandle(hSnap); +#endif } - else /* hSnap == INVALID_HANDLE_VALUE */ - rc = RTErrConvertFromWin32(GetLastError()); + CloseHandle(hSnap); } - RTLdrClose(hKernel32); } /* If we couldn't take a process snapshot for some reason or another, fall back on the NT4 compatible API. */ - if (RT_FAILURE(rc)) + if (fFallback) return rtProcWinFindTokenByProcessAndPsApi(papszNames, pSid, phToken); return fFound; } @@ -602,7 +589,13 @@ static int rtProcWinUserLogon(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 LOGON32_PROVIDER_DEFAULT, phToken); if (!fRc) - return rtProcWinMapErrorCodes(GetLastError()); + { + DWORD dwErr = GetLastError(); + int rc = rtProcWinMapErrorCodes(dwErr); + if (rc == VERR_UNRESOLVED_ERROR) + LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc)); + return rc; + } return VINF_SUCCESS; } @@ -651,8 +644,10 @@ static int rtProcWinEnvironmentCreateInternal(VOID *pvBlock, RTENV hEnv, PRTUTF1 RTStrFree(pszEntry); } } + else + break; pwch += RTUtf16Len(pwch) + 1; - if (*pwch) + if (!*pwch) break; } @@ -680,8 +675,11 @@ static int rtProcWinEnvironmentCreateInternal(VOID *pvBlock, RTENV hEnv, PRTUTF1 */ static int rtProcWinCreateEnvFromToken(HANDLE hToken, RTENV hEnv, PRTUTF16 *ppwszBlock) { + Assert(hToken); + Assert(hEnv != NIL_RTENV); + RTLDRMOD hUserenv; - int rc = RTLdrLoad("Userenv.dll", &hUserenv); + int rc = RTLdrLoadSystem("Userenv.dll", true /*fNoUnload*/, &hUserenv); if (RT_SUCCESS(rc)) { PFNCREATEENVIRONMENTBLOCK pfnCreateEnvironmentBlock; @@ -729,7 +727,7 @@ static int rtProcWinCreateEnvFromToken(HANDLE hToken, RTENV hEnv, PRTUTF16 *ppws * @param ppwszBlock Pointer to a pointer of the final UTF16 environment block. */ static int rtProcWinCreateEnvFromAccount(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain, - RTENV hEnv, PRTUTF16 *ppwszBlock) + RTENV hEnv, PRTUTF16 *ppwszBlock) { HANDLE hToken; int rc = rtProcWinUserLogon(pwszUser, pwszPassword, pwszDomain, &hToken); @@ -873,7 +871,7 @@ static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU */ phToken = fFound ? &hTokenUserDesktop : &hTokenLogon; RTLDRMOD hUserenv; - int rc = RTLdrLoad("Userenv.dll", &hUserenv); + rc = RTLdrLoadSystem("Userenv.dll", true /*fNoUnload*/, &hUserenv); if (RT_SUCCESS(rc)) { PFNLOADUSERPROFILEW pfnLoadUserProfileW; @@ -915,7 +913,9 @@ static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU NULL, /* pThreadAttributes */ TRUE, /* fInheritHandles */ dwCreationFlags, - pwszzBlock, + /** @todo Warn about exceeding 8192 bytes + * on XP and up. */ + pwszzBlock, /* lpEnvironment */ NULL, /* pCurrentDirectory */ pStartupInfo, pProcInfo); @@ -951,7 +951,11 @@ static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU if ( RT_SUCCESS(rc) && dwErr != NO_ERROR) + { rc = rtProcWinMapErrorCodes(dwErr); + if (rc == VERR_UNRESOLVED_ERROR) + LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc)); + } return rc; } @@ -967,36 +971,36 @@ static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTU RTENV hEnv, DWORD dwCreationFlags, STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags) { - RTLDRMOD hAdvAPI32; - int rc = RTLdrLoad("Advapi32.dll", &hAdvAPI32); + PFNCREATEPROCESSWITHLOGON pfnCreateProcessWithLogonW; + pfnCreateProcessWithLogonW = (PFNCREATEPROCESSWITHLOGON)RTLdrGetSystemSymbol("Advapi32.dll", "CreateProcessWithLogonW"); + if (!pfnCreateProcessWithLogonW) + return VERR_SYMBOL_NOT_FOUND; + + PRTUTF16 pwszzBlock; + int rc = rtProcWinCreateEnvFromAccount(pwszUser, pwszPassword, NULL /* Domain */, + hEnv, &pwszzBlock); if (RT_SUCCESS(rc)) { - PFNCREATEPROCESSWITHLOGON pfnCreateProcessWithLogonW; - rc = RTLdrGetSymbol(hAdvAPI32, "CreateProcessWithLogonW", (void **)&pfnCreateProcessWithLogonW); - if (RT_SUCCESS(rc)) + BOOL fRc = pfnCreateProcessWithLogonW(pwszUser, + NULL, /* lpDomain*/ + pwszPassword, + 1 /*LOGON_WITH_PROFILE*/, /* dwLogonFlags */ + pwszExec, + pwszCmdLine, + dwCreationFlags, + pwszzBlock, + NULL, /* pCurrentDirectory */ + pStartupInfo, + pProcInfo); + if (!fRc) { - PRTUTF16 pwszzBlock; - rc = rtProcWinCreateEnvFromAccount(pwszUser, pwszPassword, NULL /* Domain */, - hEnv, &pwszzBlock); - if (RT_SUCCESS(rc)) - { - BOOL fRc = pfnCreateProcessWithLogonW(pwszUser, - NULL, /* lpDomain*/ - pwszPassword, - 1 /*LOGON_WITH_PROFILE*/, /* dwLogonFlags */ - pwszExec, - pwszCmdLine, - dwCreationFlags, - pwszzBlock, - NULL, /* pCurrentDirectory */ - pStartupInfo, - pProcInfo); - if (!fRc) - rc = rtProcWinMapErrorCodes(GetLastError()); - rtProcWinDestroyEnv(pwszzBlock); - } + DWORD dwErr = GetLastError(); + rc = rtProcWinMapErrorCodes(dwErr); + if (rc == VERR_UNRESOLVED_ERROR) + LogRelFunc(("pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n", + pfnCreateProcessWithLogonW, dwErr, dwErr, rc)); } - RTLdrClose(hAdvAPI32); + rtProcWinDestroyEnv(pwszzBlock); } return rc; } @@ -1060,12 +1064,11 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER); AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER); - /** @todo search the PATH (add flag for this). */ /* * Initialize the globals. */ - int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL); + int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL); AssertRCReturn(rc, rc); /* @@ -1197,7 +1200,7 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg */ PROCESS_INFORMATION ProcInfo; RT_ZERO(ProcInfo); - DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; + DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; if (fFlags & RTPROC_FLAGS_DETACHED) dwCreationFlags |= DETACHED_PROCESS; if (fFlags & RTPROC_FLAGS_NO_WINDOW) @@ -1288,7 +1291,7 @@ RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArg RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus) { AssertReturn(!(fFlags & ~(RTPROCWAIT_FLAGS_BLOCK | RTPROCWAIT_FLAGS_NOBLOCK)), VERR_INVALID_PARAMETER); - int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL); + int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL); AssertRCReturn(rc, rc); /* @@ -1384,7 +1387,7 @@ RTR3DECL(int) RTProcTerminate(RTPROCESS Process) if (Process == NIL_RTPROCESS) return VINF_SUCCESS; - int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL); + int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL); AssertRCReturn(rc, rc); /* diff --git a/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp b/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp index 3b056cde..ab7ff7fc 100644 --- a/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp +++ b/src/VBox/Runtime/r3/win/rtProcInitExePath-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/sched-win.cpp b/src/VBox/Runtime/r3/win/sched-win.cpp index 935bd651..54b8154b 100644 --- a/src/VBox/Runtime/r3/win/sched-win.cpp +++ b/src/VBox/Runtime/r3/win/sched-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/semmutex-win.cpp b/src/VBox/Runtime/r3/win/semmutex-win.cpp index 7cdab20b..e3ec555e 100644 --- a/src/VBox/Runtime/r3/win/semmutex-win.cpp +++ b/src/VBox/Runtime/r3/win/semmutex-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/symlink-win.cpp b/src/VBox/Runtime/r3/win/symlink-win.cpp index 30332539..52f5c410 100644 --- a/src/VBox/Runtime/r3/win/symlink-win.cpp +++ b/src/VBox/Runtime/r3/win/symlink-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,8 +29,10 @@ * Header Files * *******************************************************************************/ #define LOG_GROUP RTLOGGROUP_SYMLINK +#include <Windows.h> #include <iprt/symlink.h> +#include "internal-r3-win.h" #include <iprt/assert.h> #include <iprt/err.h> @@ -40,7 +42,6 @@ #include <iprt/string.h> #include "internal/path.h" -#include <Windows.h> /******************************************************************************* @@ -133,13 +134,9 @@ RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, RTSYM static bool s_fTried = FALSE; if (!s_fTried) { - HMODULE hmod = LoadLibrary("KERNEL32.DLL"); - if (hmod) - { - PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(hmod, "CreateSymbolicLinkW"); - if (pfn) - s_pfnCreateSymbolicLinkW = pfn; - } + PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(g_hModKernel32, "CreateSymbolicLinkW"); + if (pfn) + s_pfnCreateSymbolicLinkW = pfn; s_fTried = true; } if (!s_pfnCreateSymbolicLinkW) diff --git a/src/VBox/Runtime/r3/win/thread-win.cpp b/src/VBox/Runtime/r3/win/thread-win.cpp index 788a616a..dab8cb70 100644 --- a/src/VBox/Runtime/r3/win/thread-win.cpp +++ b/src/VBox/Runtime/r3/win/thread-win.cpp @@ -68,6 +68,12 @@ DECLHIDDEN(int) rtThreadNativeInit(void) } +DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void) +{ + /* nothing to do here. */ +} + + DECLHIDDEN(void) rtThreadNativeDetach(void) { /* @@ -167,7 +173,7 @@ static void rtThreadNativeUninitComAndOle(void) AssertMsgFailed(("cComInits=%u (%#x) cOleInits=%u (%#x) - dangling COM/OLE inits!\n", cComInits, cComInits, cOleInits, cOleInits)); - HMODULE hOle32 = GetModuleHandle("OLE32"); + HMODULE hOle32 = GetModuleHandle("ole32.dll"); AssertReturnVoid(hOle32 != NULL); typedef void (WINAPI *PFNOLEUNINITIALIZE)(void); @@ -251,7 +257,7 @@ static int rtThreadGetCurrentProcessorNumber(void) static DWORD (WINAPI *pfnGetCurrentProcessorNumber)(void) = NULL; if (!fInitialized) { - HMODULE hmodKernel32 = GetModuleHandle("KERNEL32.DLL"); + HMODULE hmodKernel32 = GetModuleHandle("kernel32.dll"); if (hmodKernel32) pfnGetCurrentProcessorNumber = (DWORD (WINAPI*)(void))GetProcAddress(hmodKernel32, "GetCurrentProcessorNumber"); fInitialized = true; diff --git a/src/VBox/Runtime/r3/win/time-win.cpp b/src/VBox/Runtime/r3/win/time-win.cpp index bd4e768a..44dea140 100644 --- a/src/VBox/Runtime/r3/win/time-win.cpp +++ b/src/VBox/Runtime/r3/win/time-win.cpp @@ -39,13 +39,17 @@ #include <iprt/err.h> #include "internal/time.h" -#define USE_TICK_COUNT +/* + * Note! The selected time source be the exact same one as we use in kernel land! + */ +//#define USE_TICK_COUNT //#define USE_PERFORMANCE_COUNTER -#if 0//defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) -# define USE_INTERRUPT_TIME -#else //# define USE_FILE_TIME -#endif +//#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# define USE_INTERRUPT_TIME +//#else +//# define USE_TICK_COUNT +//#endif #ifdef USE_INTERRUPT_TIME @@ -104,6 +108,7 @@ DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void) return u64 * 100; #elif defined USE_INTERRUPT_TIME +# if 0 /* ASSUME 0x7ffe0000 is set in stone */ /* * This is exactly what we want, but we have to obtain it by non-official * means. @@ -114,16 +119,18 @@ DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void) /** @todo find official way of getting this or some more clever * detection algorithm if necessary. The com debugger class * exports this too, windbg knows it too... */ - s_pUserSharedData = (MY_ KUSER_SHARED_DATA *)(uintptr_t)0x7ffe0000; + s_pUserSharedData = (PMY_KUSER_SHARED_DATA)(uintptr_t)0x7ffe0000; } +# endif + PMY_KUSER_SHARED_DATA pUserSharedData = (PMY_KUSER_SHARED_DATA)(uintptr_t)0x7ffe0000; /* use interrupt time */ LARGE_INTEGER Time; do { - Time.HighPart = s_pUserSharedData->InterruptTime.High1Time; - Time.LowPart = s_pUserSharedData->InterruptTime.LowPart; - } while (s_pUserSharedData->InterruptTime.High2Time != Time.HighPart); + Time.HighPart = pUserSharedData->InterruptTime.High1Time; + Time.LowPart = pUserSharedData->InterruptTime.LowPart; + } while (pUserSharedData->InterruptTime.High2Time != Time.HighPart); return (uint64_t)Time.QuadPart * 100; diff --git a/src/VBox/Runtime/r3/win/timer-win.cpp b/src/VBox/Runtime/r3/win/timer-win.cpp index 08ed4ec1..a23aa17a 100644 --- a/src/VBox/Runtime/r3/win/timer-win.cpp +++ b/src/VBox/Runtime/r3/win/timer-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/tls-win.cpp b/src/VBox/Runtime/r3/win/tls-win.cpp index 2bc332b7..51e0b23b 100644 --- a/src/VBox/Runtime/r3/win/tls-win.cpp +++ b/src/VBox/Runtime/r3/win/tls-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/utf16locale-win.cpp b/src/VBox/Runtime/r3/win/utf16locale-win.cpp index 40d99bb2..ccb51ade 100644 --- a/src/VBox/Runtime/r3/win/utf16locale-win.cpp +++ b/src/VBox/Runtime/r3/win/utf16locale-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/win/uuid-win.cpp b/src/VBox/Runtime/r3/win/uuid-win.cpp index 0d91df79..ef1a42bc 100644 --- a/src/VBox/Runtime/r3/win/uuid-win.cpp +++ b/src/VBox/Runtime/r3/win/uuid-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/r3/xml.cpp b/src/VBox/Runtime/r3/xml.cpp index a753f34c..708e41fb 100644 --- a/src/VBox/Runtime/r3/xml.cpp +++ b/src/VBox/Runtime/r3/xml.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007-2011 Oracle Corporation + * Copyright (C) 2007-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,6 +24,10 @@ * terms and conditions of either the GPL or the CDDL or both. */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ #include <iprt/dir.h> #include <iprt/file.h> #include <iprt/err.h> @@ -42,14 +46,11 @@ #include <libxml/xmlschemas.h> #include <map> -#include <boost/shared_ptr.hpp> -//////////////////////////////////////////////////////////////////////////////// -// -// globals -// -//////////////////////////////////////////////////////////////////////////////// +/******************************************************************************* +* Global Variables * +*******************************************************************************/ /** * Global module initialization structure. This is to wrap non-reentrant bits * of libxml, among other things. @@ -58,8 +59,7 @@ * module initialization and cleanup. There must be only one global variable of * this structure. */ -static -class Global +static class Global { public: @@ -93,8 +93,7 @@ public: RTCLockMtx lock; } sxml; /* XXX naming this xml will break with gcc-3.3 */ -} -gGlobal; +} gGlobal; @@ -131,8 +130,7 @@ XmlError::XmlError(xmlErrorPtr aErr) * Composes a single message for the given error. The caller must free the * returned string using RTStrFree() when no more necessary. */ -// static -char *XmlError::Format(xmlErrorPtr aErr) +/* static */ char *XmlError::Format(xmlErrorPtr aErr) { const char *msg = aErr->message ? aErr->message : "<none>"; size_t msgLen = strlen(msg); @@ -156,7 +154,7 @@ EIPRTFailure::EIPRTFailure(int aRC, const char *pcszContext, ...) va_start(args, pcszContext); RTStrAPrintfV(&pszContext2, pcszContext, args); char *newMsg; - RTStrAPrintf(&newMsg, "%s: %d (%s)", pszContext2, aRC, RTErrGetShort(aRC)); + RTStrAPrintf(&newMsg, "%s: %d(%s)", pszContext2, aRC, RTErrGetShort(aRC)); setWhat(newMsg); RTStrFree(newMsg); RTStrFree(pszContext2); @@ -241,7 +239,7 @@ File::~File() delete m; } -const char* File::uri() const +const char *File::uri() const { return m->strFileName.c_str(); } @@ -291,19 +289,17 @@ int File::read(char *aBuf, int aLen) int File::write(const char *aBuf, int aLen) { size_t len = aLen; - int vrc = RTFileWrite (m->handle, aBuf, len, &len); - if (RT_SUCCESS (vrc)) + int vrc = RTFileWrite(m->handle, aBuf, len, &len); + if (RT_SUCCESS(vrc)) return (int)len; throw EIPRTFailure(vrc, "Runtime error writing to file '%s'", m->strFileName.c_str()); - - return -1 /* failure */; } void File::truncate() { - int vrc = RTFileSetSize (m->handle, pos()); - if (RT_SUCCESS (vrc)) + int vrc = RTFileSetSize(m->handle, pos()); + if (RT_SUCCESS(vrc)) return; throw EIPRTFailure(vrc, "Runtime error truncating file '%s'", m->strFileName.c_str()); @@ -318,7 +314,7 @@ void File::truncate() struct MemoryBuf::Data { Data() - : buf (NULL), len (0), uri (NULL), pos (0) {} + : buf(NULL), len(0), uri(NULL), pos(0) {} const char *buf; size_t len; @@ -327,20 +323,20 @@ struct MemoryBuf::Data size_t pos; }; -MemoryBuf::MemoryBuf (const char *aBuf, size_t aLen, const char *aURI /* = NULL */) - : m (new Data()) +MemoryBuf::MemoryBuf(const char *aBuf, size_t aLen, const char *aURI /* = NULL */) + : m(new Data()) { if (aBuf == NULL) - throw EInvalidArg (RT_SRC_POS); + throw EInvalidArg(RT_SRC_POS); m->buf = aBuf; m->len = aLen; - m->uri = RTStrDup (aURI); + m->uri = RTStrDup(aURI); } MemoryBuf::~MemoryBuf() { - RTStrFree (m->uri); + RTStrFree(m->uri); } const char *MemoryBuf::uri() const @@ -353,9 +349,9 @@ uint64_t MemoryBuf::pos() const return m->pos; } -void MemoryBuf::setPos (uint64_t aPos) +void MemoryBuf::setPos(uint64_t aPos) { - size_t off = (size_t) aPos; + size_t off = (size_t)aPos; if ((uint64_t) off != aPos) throw EInvalidArg(); @@ -365,13 +361,13 @@ void MemoryBuf::setPos (uint64_t aPos) m->pos = off; } -int MemoryBuf::read (char *aBuf, int aLen) +int MemoryBuf::read(char *aBuf, int aLen) { if (m->pos >= m->len) return 0 /* nothing to read */; size_t len = m->pos + aLen < m->len ? aLen : m->len - m->pos; - memcpy (aBuf, m->buf + m->pos, len); + memcpy(aBuf, m->buf + m->pos, len); m->pos += len; return (int)len; @@ -422,90 +418,43 @@ xmlParserInput* GlobalLock::callDefaultLoader(const char *aURI, return gGlobal.sxml.defaultEntityLoader(aURI, aID, aCtxt); } + + //////////////////////////////////////////////////////////////////////////////// // // Node class // //////////////////////////////////////////////////////////////////////////////// -struct Node::Data -{ - struct compare_const_char - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - // attributes, if this is an element; can be empty - typedef std::map<const char*, boost::shared_ptr<AttributeNode>, compare_const_char > AttributesMap; - AttributesMap attribs; - - // child elements, if this is an element; can be empty - typedef std::list< boost::shared_ptr<Node> > InternalNodesList; - InternalNodesList children; -}; - Node::Node(EnumType type, Node *pParent, - xmlNode *plibNode, - xmlAttr *plibAttr) - : m_Type(type), - m_pParent(pParent), - m_plibNode(plibNode), - m_plibAttr(plibAttr), - m_pcszNamespacePrefix(NULL), - m_pcszNamespaceHref(NULL), - m_pcszName(NULL), - m(new Data) + PRTLISTANCHOR pListAnchor, + xmlNode *pLibNode, + xmlAttr *pLibAttr) + : m_Type(type) + , m_pParent(pParent) + , m_pLibNode(pLibNode) + , m_pLibAttr(pLibAttr) + , m_pcszNamespacePrefix(NULL) + , m_pcszNamespaceHref(NULL) + , m_pcszName(NULL) + , m_pParentListAnchor(pListAnchor) { + RTListInit(&m_listEntry); } Node::~Node() { - delete m; } /** - * Private implementation. - * @param elmRoot + * Returns the name of the node, which is either the element name or + * the attribute name. For other node types it probably returns NULL. + * @return */ -void Node::buildChildren(const ElementNode &elmRoot) // private +const char *Node::getName() const { - // go thru this element's attributes - xmlAttr *plibAttr = m_plibNode->properties; - while (plibAttr) - { - const char *pcszKey; - boost::shared_ptr<AttributeNode> pNew(new AttributeNode(elmRoot, this, plibAttr, &pcszKey)); - // store - m->attribs[pcszKey] = pNew; - - plibAttr = plibAttr->next; - } - - // go thru this element's child elements - xmlNodePtr plibNode = m_plibNode->children; - while (plibNode) - { - boost::shared_ptr<Node> pNew; - - if (plibNode->type == XML_ELEMENT_NODE) - pNew = boost::shared_ptr<Node>(new ElementNode(&elmRoot, this, plibNode)); - else if (plibNode->type == XML_TEXT_NODE) - pNew = boost::shared_ptr<Node>(new ContentNode(this, plibNode)); - if (pNew) - { - // store - m->children.push_back(pNew); - - // recurse for this child element to get its own children - pNew->buildChildren(elmRoot); - } - - plibNode = plibNode->next; - } + return m_pcszName; } /** @@ -513,9 +462,19 @@ void Node::buildChildren(const ElementNode &elmRoot) // private * the attribute name. For other node types it probably returns NULL. * @return */ -const char* Node::getName() const +const char *Node::getPrefix() const { - return m_pcszName; + return m_pcszNamespacePrefix; +} + +/** + * Returns the XML namespace URI, which is the attribute name. For other node types it probably + * returns NULL. + * @return + */ +const char *Node::getNamespaceURI() const +{ + return m_pcszNamespaceHref; } /** @@ -524,7 +483,7 @@ const char* Node::getName() const * @param pcsz * @return */ -bool Node::nameEquals(const char *pcszNamespace, const char *pcsz) const +bool Node::nameEqualsNS(const char *pcszNamespace, const char *pcsz) const { if (m_pcszName == pcsz) return true; @@ -546,24 +505,52 @@ bool Node::nameEquals(const char *pcszNamespace, const char *pcsz) const } /** + * Variant of nameEquals that checks the namespace as well. + * + * @returns true if equal, false if not. + * @param pcsz The element name. + * @param cchMax The maximum number of character from @a pcsz to + * match. + * @param pcszNamespace The name space prefix or NULL (default). + */ +bool Node::nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace /* = NULL*/) const +{ + /* Match the name. */ + if (!m_pcszName) + return false; + if (!pcsz || cchMax == 0) + return false; + if (strncmp(m_pcszName, pcsz, cchMax)) + return false; + if (strlen(m_pcszName) > cchMax) + return false; + + /* Match name space. */ + if (!pcszNamespace) + return true; /* NULL, anything goes. */ + if (!m_pcszNamespacePrefix) + return false; /* Element has no namespace. */ + return !strcmp(m_pcszNamespacePrefix, pcszNamespace); +} + +/** * Returns the value of a node. If this node is an attribute, returns * the attribute value; if this node is an element, then this returns * the element text content. * @return */ -const char* Node::getValue() const +const char *Node::getValue() const { - if ( (m_plibAttr) - && (m_plibAttr->children) - ) + if ( m_pLibAttr + && m_pLibAttr->children + ) // libxml hides attribute values in another node created as a // single child of the attribute node, and it's in the content field - return (const char*)m_plibAttr->children->content; + return (const char *)m_pLibAttr->children->content; - if ( (m_plibNode) - && (m_plibNode->children) - ) - return (const char*)m_plibNode->children->content; + if ( m_pLibNode + && m_pLibNode->children) + return (const char *)m_pLibNode->children->content; return NULL; } @@ -643,39 +630,132 @@ bool Node::copyValue(uint64_t &i) const */ int Node::getLineNumber() const { - if (m_plibAttr) - return m_pParent->m_plibNode->line; + if (m_pLibAttr) + return m_pParent->m_pLibNode->line; - return m_plibNode->line; + return m_pLibNode->line; } /** * Private element constructor. - * @param pelmRoot - * @param pParent - * @param plibNode + * + * @param pElmRoot Pointer to the root element. + * @param pParent Pointer to the parent element (always an ElementNode, + * despite the type). NULL for the root node. + * @param pListAnchor Pointer to the m_children member of the parent. NULL + * for the root node. + * @param pLibNode Pointer to the libxml2 node structure. */ -ElementNode::ElementNode(const ElementNode *pelmRoot, +ElementNode::ElementNode(const ElementNode *pElmRoot, Node *pParent, - xmlNode *plibNode) + PRTLISTANCHOR pListAnchor, + xmlNode *pLibNode) : Node(IsElement, pParent, - plibNode, + pListAnchor, + pLibNode, NULL) { - if (!(m_pelmRoot = pelmRoot)) - // NULL passed, then this is the root element - m_pelmRoot = this; + m_pElmRoot = pElmRoot ? pElmRoot : this; // If NULL is passed, then this is the root element. + m_pcszName = (const char *)pLibNode->name; - m_pcszName = (const char*)plibNode->name; + if (pLibNode->ns) + { + m_pcszNamespacePrefix = (const char *)m_pLibNode->ns->prefix; + m_pcszNamespaceHref = (const char *)m_pLibNode->ns->href; + } - if (plibNode->ns) + RTListInit(&m_children); + RTListInit(&m_attributes); +} + +ElementNode::~ElementNode() +{ + Node *pCur, *pNext; + RTListForEachSafeCpp(&m_children, pCur, pNext, Node, m_listEntry) { - m_pcszNamespacePrefix = (const char*)m_plibNode->ns->prefix; - m_pcszNamespaceHref = (const char*)m_plibNode->ns->href; + delete pCur; } + RTListInit(&m_children); + + RTListForEachSafeCpp(&m_attributes, pCur, pNext, Node, m_listEntry) + { + delete pCur; + } + RTListInit(&m_attributes); } + +/** + * Gets the next tree element in a full tree enumeration. + * + * @returns Pointer to the next element in the tree, NULL if we're done. + * @param pElmRoot The root of the tree we're enumerating. NULL if + * it's the entire tree. + */ +ElementNode const *ElementNode::getNextTreeElement(ElementNode const *pElmRoot /*= NULL */) const +{ + /* + * Consider children first. + */ + ElementNode const *pChild = getFirstChildElement(); + if (pChild) + return pChild; + + /* + * Then siblings, aunts and uncles. + */ + ElementNode const *pCur = this; + do + { + ElementNode const *pSibling = pCur->getNextSibilingElement(); + if (pSibling != NULL) + return pSibling; + + pCur = static_cast<const xml::ElementNode *>(pCur->m_pParent); + Assert(pCur || pCur == pElmRoot); + } while (pCur != pElmRoot); + + return NULL; +} + + +/** + * Private implementation. + * + * @param pElmRoot The root element. + */ +/*static*/ void ElementNode::buildChildren(ElementNode *pElmRoot) // protected +{ + for (ElementNode *pCur = pElmRoot; pCur; pCur = pCur->getNextTreeElement(pElmRoot)) + { + /* + * Go thru this element's attributes creating AttributeNodes for them. + */ + for (xmlAttr *pLibAttr = pCur->m_pLibNode->properties; pLibAttr; pLibAttr = pLibAttr->next) + { + AttributeNode *pNew = new AttributeNode(pElmRoot, pCur, &pCur->m_attributes, pLibAttr); + RTListAppend(&pCur->m_attributes, &pNew->m_listEntry); + } + + /* + * Go thru this element's child elements (element and text nodes). + */ + for (xmlNodePtr pLibNode = pCur->m_pLibNode->children; pLibNode; pLibNode = pLibNode->next) + { + Node *pNew; + if (pLibNode->type == XML_ELEMENT_NODE) + pNew = new ElementNode(pElmRoot, pCur, &pCur->m_children, pLibNode); + else if (pLibNode->type == XML_TEXT_NODE) + pNew = new ContentNode(pCur, &pCur->m_children, pLibNode); + else + continue; + RTListAppend(&pCur->m_children, &pNew->m_listEntry); + } + } +} + + /** * Builds a list of direct child elements of the current element that * match the given string; if pcszMatch is NULL, all direct child @@ -689,18 +769,16 @@ int ElementNode::getChildElements(ElementNodesList &children, const { int i = 0; - for (Data::InternalNodesList::iterator it = m->children.begin(); - it != m->children.end(); - ++it) + Node *p; + RTListForEachCpp(&m_children, p, Node, m_listEntry) { // export this child node if ... - Node *p = it->get(); if (p->isElement()) - if ( (!pcszMatch) // the caller wants all nodes or - || (!strcmp(pcszMatch, p->getName())) // the element name matches + if ( !pcszMatch // ... the caller wants all nodes or ... + || !strcmp(pcszMatch, p->getName()) // ... the element name matches. ) { - children.push_back(static_cast<ElementNode*>(p)); + children.push_back(static_cast<ElementNode *>(p)); ++i; } } @@ -714,25 +792,18 @@ int ElementNode::getChildElements(ElementNodesList &children, * @param pcszMatch Element name to match. * @return */ -const ElementNode* ElementNode::findChildElement(const char *pcszNamespace, - const char *pcszMatch) - const +const ElementNode *ElementNode::findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const { - Data::InternalNodesList::const_iterator - it, - last = m->children.end(); - for (it = m->children.begin(); - it != last; - ++it) + Node *p; + RTListForEachCpp(&m_children, p, Node, m_listEntry) { - if ((**it).isElement()) + if (p->isElement()) { - ElementNode *pelm = static_cast<ElementNode*>((*it).get()); - if (pelm->nameEquals(pcszNamespace, pcszMatch)) + ElementNode *pelm = static_cast<ElementNode*>(p); + if (pelm->nameEqualsNS(pcszNamespace, pcszMatch)) return pelm; } } - return NULL; } @@ -741,58 +812,154 @@ const ElementNode* ElementNode::findChildElement(const char *pcszNamespace, * @param pcszId identifier to look for. * @return child element or NULL if not found. */ -const ElementNode* ElementNode::findChildElementFromId(const char *pcszId) const -{ - Data::InternalNodesList::const_iterator - it, - last = m->children.end(); - for (it = m->children.begin(); - it != last; - ++it) +const ElementNode *ElementNode::findChildElementFromId(const char *pcszId) const +{ + const Node *p; + RTListForEachCpp(&m_children, p, Node, m_listEntry) { - if ((**it).isElement()) + if (p->isElement()) { - ElementNode *pelm = static_cast<ElementNode*>((*it).get()); - const AttributeNode *pAttr; - if ( ((pAttr = pelm->findAttribute("id"))) - && (!strcmp(pAttr->getValue(), pcszId)) - ) - return pelm; + const ElementNode *pElm = static_cast<const ElementNode *>(p); + const AttributeNode *pAttr = pElm->findAttribute("id"); + if (pAttr && !strcmp(pAttr->getValue(), pcszId)) + return pElm; } } + return NULL; +} + +const ElementNode *ElementNode::findChildElementP(const char *pcszPath, const char *pcszNamespace /*= NULL*/) const +{ + size_t cchThis = strchr(pcszPath, '/') - pcszPath; + if (cchThis == (size_t)((const char *)0 - pcszPath)) + return findChildElementNS(pcszNamespace, pcszPath); + + /** @todo Can be done without recursion as we have both sibling lists and parent + * pointers in this variant. */ + const Node *p; + RTListForEachCpp(&m_children, p, Node, m_listEntry) + { + if (p->isElement()) + { + const ElementNode *pElm = static_cast<const ElementNode *>(p); + if (pElm->nameEqualsN(pcszPath, cchThis, pcszNamespace)) + { + pElm = findChildElementP(pcszPath + cchThis, pcszNamespace); + if (pElm) + return pElm; + } + } + } + + return NULL; +} + +const ElementNode *ElementNode::getFirstChildElement() const +{ + const Node *p; + RTListForEachCpp(&m_children, p, Node, m_listEntry) + { + if (p->isElement()) + return static_cast<const ElementNode *>(p); + } + return NULL; +} + +const ElementNode *ElementNode::getLastChildElement() const +{ + const Node *p; + RTListForEachReverseCpp(&m_children, p, Node, m_listEntry) + { + if (p->isElement()) + return static_cast<const ElementNode *>(p); + } return NULL; } +const ElementNode *ElementNode::getPrevSibilingElement() const +{ + if (!m_pParent) + return NULL; + const Node *pSibling = this; + for (;;) + { + pSibling = RTListGetPrevCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry); + if (!pSibling) + return NULL; + if (pSibling->isElement()) + return static_cast<const ElementNode *>(pSibling); + } +} + +const ElementNode *ElementNode::getNextSibilingElement() const +{ + if (!m_pParent) + return NULL; + const Node *pSibling = this; + for (;;) + { + pSibling = RTListGetNextCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry); + if (!pSibling) + return NULL; + if (pSibling->isElement()) + return static_cast<const ElementNode *>(pSibling); + } +} + +const ElementNode *ElementNode::findPrevSibilingElement(const char *pcszMatch, const char *pcszNamespace /*= NULL*/) const +{ + if (!m_pParent) + return NULL; + const Node *pSibling = this; + for (;;) + { + pSibling = RTListGetPrevCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry); + if (!pSibling) + return NULL; + if (pSibling->isElement()) + { + const ElementNode *pElem = static_cast<const ElementNode *>(pSibling); + if (pElem->nameEqualsNS(pcszNamespace, pcszMatch)) + return pElem; + } + } +} + +const ElementNode *ElementNode::findNextSibilingElement(const char *pcszMatch, const char *pcszNamespace /*= NULL*/) const +{ + if (!m_pParent) + return NULL; + const Node *pSibling = this; + for (;;) + { + pSibling = RTListGetNextCpp(m_pParentListAnchor, pSibling, const Node, m_listEntry); + if (!pSibling) + return NULL; + if (pSibling->isElement()) + { + const ElementNode *pElem = static_cast<const ElementNode *>(pSibling); + if (pElem->nameEqualsNS(pcszNamespace, pcszMatch)) + return pElem; + } + } +} + + /** * Looks up the given attribute node in this element's attribute map. * - * With respect to namespaces, the internal attributes map stores namespace - * prefixes with attribute names only if the attribute uses a non-default - * namespace. As a result, the following rules apply: - * - * -- To find attributes from a non-default namespace, pcszMatch must not - * be prefixed with a namespace. - * - * -- To find attributes from the default namespace (or if the document does - * not use namespaces), pcszMatch must be prefixed with the namespace - * prefix and a colon. - * - * For example, if the document uses the "vbox:" namespace by default, you - * must omit "vbox:" from pcszMatch to find such attributes, whether they - * are specifed in the xml or not. - * - * @param pcszMatch - * @return + * @param pcszMatch The name of the attribute to find. + * @param pcszNamespace The attribute name space prefix or NULL. */ -const AttributeNode* ElementNode::findAttribute(const char *pcszMatch) const +const AttributeNode *ElementNode::findAttribute(const char *pcszMatch, const char *pcszNamespace /*= NULL*/) const { - Data::AttributesMap::const_iterator it; - - it = m->attribs.find(pcszMatch); - if (it != m->attribs.end()) - return it->second.get(); - + AttributeNode *p; + RTListForEachCpp(&m_attributes, p, AttributeNode, m_listEntry) + { + if (p->nameEqualsNS(pcszNamespace, pcszMatch)) + return p; + } return NULL; } @@ -800,19 +967,19 @@ const AttributeNode* ElementNode::findAttribute(const char *pcszMatch) const * Convenience method which attempts to find the attribute with the given * name and returns its value as a string. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param ppcsz out: attribute value - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param ppcsz Where to return the attribute. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, const char *&ppcsz) const +bool ElementNode::getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace /*= NULL*/) const { - const Node* pAttr; - if ((pAttr = findAttribute(pcszMatch))) + const AttributeNode *pAttr = findAttribute(pcszMatch, pcszNamespace); + if (pAttr) { - ppcsz = pAttr->getValue(); + *ppcsz = pAttr->getValue(); return true; } - return false; } @@ -820,16 +987,20 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, const char *&ppcsz) c * Convenience method which attempts to find the attribute with the given * name and returns its value as a string. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param str out: attribute value; overwritten only if attribute was found - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param pStr Pointer to the string object that should receive the + * attribute value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. + * + * @throws Whatever the string class may throw on assignment. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, RTCString &str) const +bool ElementNode::getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace /*= NULL*/) const { - const Node* pAttr; - if ((pAttr = findAttribute(pcszMatch))) + const AttributeNode *pAttr = findAttribute(pcszMatch, pcszNamespace); + if (pAttr) { - str = pAttr->getValue(); + *pStr = pAttr->getValue(); return true; } @@ -839,15 +1010,18 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, RTCString &str) const /** * Like getAttributeValue (ministring variant), but makes sure that all backslashes * are converted to forward slashes. - * @param pcszMatch - * @param str - * @return + * + * @param pcszMatch Name of attribute to find. + * @param pStr Pointer to the string object that should + * receive the attribute path value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValuePath(const char *pcszMatch, RTCString &str) const +bool ElementNode::getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace /*= NULL*/) const { - if (getAttributeValue(pcszMatch, str)) + if (getAttributeValue(pcszMatch, pStr, pcszNamespace)) { - str.findReplace('\\', '/'); + pStr->findReplace('\\', '/'); return true; } @@ -856,85 +1030,85 @@ bool ElementNode::getAttributeValuePath(const char *pcszMatch, RTCString &str) c /** * Convenience method which attempts to find the attribute with the given - * name and returns its value as a signed integer. This calls - * RTStrToInt32Ex internally and will only output the integer if that - * function returns no error. + * name and returns its value as a signed 32-bit integer. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param i out: attribute value; overwritten only if attribute was found - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param piValue Where to return the value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, int32_t &i) const +bool ElementNode::getAttributeValue(const char *pcszMatch, int32_t *piValue, const char *pcszNamespace /*= NULL*/) const { - const char *pcsz; - if ( (getAttributeValue(pcszMatch, pcsz)) - && (VINF_SUCCESS == RTStrToInt32Ex(pcsz, NULL, 0, &i)) - ) - return true; - + const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace); + if (pcsz) + { + int rc = RTStrToInt32Ex(pcsz, NULL, 0, piValue); + if (rc == VINF_SUCCESS) + return true; + } return false; } /** * Convenience method which attempts to find the attribute with the given - * name and returns its value as an unsigned integer.This calls - * RTStrToUInt32Ex internally and will only output the integer if that - * function returns no error. + * name and returns its value as an unsigned 32-bit integer. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param i out: attribute value; overwritten only if attribute was found - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param puValue Where to return the value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, uint32_t &i) const +bool ElementNode::getAttributeValue(const char *pcszMatch, uint32_t *puValue, const char *pcszNamespace /*= NULL*/) const { - const char *pcsz; - if ( (getAttributeValue(pcszMatch, pcsz)) - && (VINF_SUCCESS == RTStrToUInt32Ex(pcsz, NULL, 0, &i)) - ) - return true; - + const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace); + if (pcsz) + { + int rc = RTStrToUInt32Ex(pcsz, NULL, 0, puValue); + if (rc == VINF_SUCCESS) + return true; + } return false; } /** * Convenience method which attempts to find the attribute with the given - * name and returns its value as a signed long integer. This calls - * RTStrToInt64Ex internally and will only output the integer if that - * function returns no error. + * name and returns its value as a signed 64-bit integer. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param i out: attribute value - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param piValue Where to return the value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, int64_t &i) const +bool ElementNode::getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace /*= NULL*/) const { - const char *pcsz; - if ( (getAttributeValue(pcszMatch, pcsz)) - && (VINF_SUCCESS == RTStrToInt64Ex(pcsz, NULL, 0, &i)) - ) - return true; - + const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace); + if (pcsz) + { + int rc = RTStrToInt64Ex(pcsz, NULL, 0, piValue); + if (rc == VINF_SUCCESS) + return true; + } return false; } /** * Convenience method which attempts to find the attribute with the given - * name and returns its value as an unsigned long integer.This calls - * RTStrToUInt64Ex internally and will only output the integer if that - * function returns no error. + * name and returns its value as an unsigned 64-bit integer. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param i out: attribute value; overwritten only if attribute was found - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param puValue Where to return the value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, uint64_t &i) const +bool ElementNode::getAttributeValue(const char *pcszMatch, uint64_t *puValue, const char *pcszNamespace /*= NULL*/) const { - const char *pcsz; - if ( (getAttributeValue(pcszMatch, pcsz)) - && (VINF_SUCCESS == RTStrToUInt64Ex(pcsz, NULL, 0, &i)) - ) - return true; - + const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace); + if (pcsz) + { + int rc = RTStrToUInt64Ex(pcsz, NULL, 0, puValue); + if (rc == VINF_SUCCESS) + return true; + } return false; } @@ -943,29 +1117,30 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, uint64_t &i) const * name and returns its value as a boolean. This accepts "true", "false", * "yes", "no", "1" or "0" as valid values. * - * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) - * @param f out: attribute value; overwritten only if attribute was found - * @return TRUE if attribute was found and str was thus updated. + * @param pcszMatch Name of attribute to find. + * @param pfValue Where to return the value. + * @param pcszNamespace The attribute name space prefix or NULL. + * @returns Boolean success indicator. */ -bool ElementNode::getAttributeValue(const char *pcszMatch, bool &f) const +bool ElementNode::getAttributeValue(const char *pcszMatch, bool *pfValue, const char *pcszNamespace /*= NULL*/) const { - const char *pcsz; - if (getAttributeValue(pcszMatch, pcsz)) + const char *pcsz = findAttributeValue(pcszMatch, pcszNamespace); + if (pcsz) { - if ( (!strcmp(pcsz, "true")) - || (!strcmp(pcsz, "yes")) - || (!strcmp(pcsz, "1")) + if ( !strcmp(pcsz, "true") + || !strcmp(pcsz, "yes") + || !strcmp(pcsz, "1") ) { - f = true; + *pfValue = true; return true; } - if ( (!strcmp(pcsz, "false")) - || (!strcmp(pcsz, "no")) - || (!strcmp(pcsz, "0")) + if ( !strcmp(pcsz, "false") + || !strcmp(pcsz, "no") + || !strcmp(pcsz, "0") ) { - f = false; + *pfValue = false; return true; } } @@ -973,6 +1148,81 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, bool &f) const return false; } + +bool ElementNode::getElementValue(int32_t *piValue) const +{ + const char *pszValue = getValue(); + if (pszValue) + { + int rc = RTStrToInt32Ex(pszValue, NULL, 0, piValue); + if (rc == VINF_SUCCESS) + return true; + } + return false; +} + +bool ElementNode::getElementValue(uint32_t *puValue) const +{ + const char *pszValue = getValue(); + if (pszValue) + { + int rc = RTStrToUInt32Ex(pszValue, NULL, 0, puValue); + if (rc == VINF_SUCCESS) + return true; + } + return false; +} + +bool ElementNode::getElementValue(int64_t *piValue) const +{ + const char *pszValue = getValue(); + if (pszValue) + { + int rc = RTStrToInt64Ex(pszValue, NULL, 0, piValue); + if (rc == VINF_SUCCESS) + return true; + } + return false; +} + +bool ElementNode::getElementValue(uint64_t *puValue) const +{ + const char *pszValue = getValue(); + if (pszValue) + { + int rc = RTStrToUInt64Ex(pszValue, NULL, 0, puValue); + if (rc == VINF_SUCCESS) + return true; + } + return false; +} + +bool ElementNode::getElementValue(bool *pfValue) const +{ + const char *pszValue = getValue(); + if (pszValue) + { + if ( !strcmp(pszValue, "true") + || !strcmp(pszValue, "yes") + || !strcmp(pszValue, "1") + ) + { + *pfValue = true; + return true; + } + if ( !strcmp(pszValue, "false") + || !strcmp(pszValue, "no") + || !strcmp(pszValue, "0") + ) + { + *pfValue = true; + return true; + } + } + return false; +} + + /** * Creates a new child element node and appends it to the list * of children in "this". @@ -980,23 +1230,22 @@ bool ElementNode::getAttributeValue(const char *pcszMatch, bool &f) const * @param pcszElementName * @return */ -ElementNode* ElementNode::createChild(const char *pcszElementName) +ElementNode *ElementNode::createChild(const char *pcszElementName) { // we must be an element, not an attribute - if (!m_plibNode) + if (!m_pLibNode) throw ENodeIsNotElement(RT_SRC_POS); // libxml side: create new node - xmlNode *plibNode; - if (!(plibNode = xmlNewNode(NULL, // namespace + xmlNode *pLibNode; + if (!(pLibNode = xmlNewNode(NULL, // namespace (const xmlChar*)pcszElementName))) throw std::bad_alloc(); - xmlAddChild(m_plibNode, plibNode); + xmlAddChild(m_pLibNode, pLibNode); // now wrap this in C++ - ElementNode *p = new ElementNode(m_pelmRoot, this, plibNode); - boost::shared_ptr<ElementNode> pNew(p); - m->children.push_back(pNew); + ElementNode *p = new ElementNode(m_pElmRoot, this, &m_children, pLibNode); + RTListAppend(&m_children, &p->m_listEntry); return p; } @@ -1009,18 +1258,17 @@ ElementNode* ElementNode::createChild(const char *pcszElementName) * @param pcszContent * @return */ -ContentNode* ElementNode::addContent(const char *pcszContent) +ContentNode *ElementNode::addContent(const char *pcszContent) { // libxml side: create new node - xmlNode *plibNode; - if (!(plibNode = xmlNewText((const xmlChar*)pcszContent))) + xmlNode *pLibNode = xmlNewText((const xmlChar*)pcszContent); + if (!pLibNode) throw std::bad_alloc(); - xmlAddChild(m_plibNode, plibNode); + xmlAddChild(m_pLibNode, pLibNode); // now wrap this in C++ - ContentNode *p = new ContentNode(this, plibNode); - boost::shared_ptr<ContentNode> pNew(p); - m->children.push_back(pNew); + ContentNode *p = new ContentNode(this, &m_children, pLibNode); + RTListAppend(&m_children, &p->m_listEntry); return p; } @@ -1032,42 +1280,40 @@ ContentNode* ElementNode::addContent(const char *pcszContent) * otherwise a new attribute is created. Returns the attribute node * that was either created or changed. * - * @param pcszName - * @param pcszValue - * @return + * @param pcszName The attribute name. + * @param pcszValue The attribute value. + * @return Pointer to the attribute node that was created or modified. */ -AttributeNode* ElementNode::setAttribute(const char *pcszName, const char *pcszValue) +AttributeNode *ElementNode::setAttribute(const char *pcszName, const char *pcszValue) { - AttributeNode *pattrReturn; - Data::AttributesMap::const_iterator it; - - it = m->attribs.find(pcszName); - if (it == m->attribs.end()) - { - // libxml side: xmlNewProp creates an attribute - xmlAttr *plibAttr = xmlNewProp(m_plibNode, (xmlChar*)pcszName, (xmlChar*)pcszValue); - - // C++ side: create an attribute node around it - const char *pcszKey; - boost::shared_ptr<AttributeNode> pNew(new AttributeNode(*m_pelmRoot, this, plibAttr, &pcszKey)); - // store - m->attribs[pcszKey] = pNew; - pattrReturn = pNew.get(); - } - else + /* + * Do we already have an attribute and should we just update it? + */ + AttributeNode *pAttr; + RTListForEachCpp(&m_attributes, pAttr, AttributeNode, m_listEntry) { - // overwrite existing libxml attribute node - xmlAttrPtr plibAttr = xmlSetProp(m_plibNode, (xmlChar*)pcszName, (xmlChar*)pcszValue); - - // and fix our existing C++ side around it - boost::shared_ptr<AttributeNode> pattr = it->second; - pattr->m_plibAttr = plibAttr; // in case the xmlAttrPtr is different, I'm not sure + if (pAttr->nameEquals(pcszName)) + { + /* Overwrite existing libxml attribute node ... */ + xmlAttrPtr pLibAttr = xmlSetProp(m_pLibNode, (xmlChar *)pcszName, (xmlChar *)pcszValue); - pattrReturn = pattr.get(); + /* ... and update our C++ wrapper in case the attrib pointer changed. */ + pAttr->m_pLibAttr = pLibAttr; + return pAttr; + } } - return pattrReturn; + /* + * No existing attribute, create a new one. + */ + /* libxml side: xmlNewProp creates an attribute. */ + xmlAttr *pLibAttr = xmlNewProp(m_pLibNode, (xmlChar *)pcszName, (xmlChar *)pcszValue); + + /* C++ side: Create an attribute node around it. */ + pAttr = new AttributeNode(m_pElmRoot, this, &m_attributes, pLibAttr); + RTListAppend(&m_attributes, &pAttr->m_listEntry); + return pAttr; } /** @@ -1196,53 +1442,41 @@ AttributeNode* ElementNode::setAttribute(const char *pcszName, bool f) } /** - * Private constructor for a new attribute node. This one is special: - * in ppcszKey, it returns a pointer to a string buffer that should be - * used to index the attribute correctly with namespaces. + * Private constructor for a new attribute node. * - * @param pParent - * @param elmRoot - * @param plibAttr - * @param ppcszKey + * @param pElmRoot Pointer to the root element. Needed for getting the + * default name space. + * @param pParent Pointer to the parent element (always an ElementNode, + * despite the type). NULL for the root node. + * @param pListAnchor Pointer to the m_children member of the parent. NULL + * for the root node. + * @param pLibNode Pointer to the libxml2 node structure. */ -AttributeNode::AttributeNode(const ElementNode &elmRoot, +AttributeNode::AttributeNode(const ElementNode *pElmRoot, Node *pParent, - xmlAttr *plibAttr, - const char **ppcszKey) + PRTLISTANCHOR pListAnchor, + xmlAttr *pLibAttr) : Node(IsAttribute, pParent, + pListAnchor, NULL, - plibAttr) + pLibAttr) { - m_pcszName = (const char*)plibAttr->name; + m_pcszName = (const char *)pLibAttr->name; - *ppcszKey = m_pcszName; - - if ( plibAttr->ns - && plibAttr->ns->prefix - ) + if ( pLibAttr->ns + && pLibAttr->ns->prefix) { - m_pcszNamespacePrefix = (const char*)plibAttr->ns->prefix; - m_pcszNamespaceHref = (const char*)plibAttr->ns->href; - - if ( !elmRoot.m_pcszNamespaceHref - || (strcmp(m_pcszNamespaceHref, elmRoot.m_pcszNamespaceHref)) - ) - { - // not default namespace: - m_strKey = m_pcszNamespacePrefix; - m_strKey.append(':'); - m_strKey.append(m_pcszName); - - *ppcszKey = m_strKey.c_str(); - } + m_pcszNamespacePrefix = (const char *)pLibAttr->ns->prefix; + m_pcszNamespaceHref = (const char *)pLibAttr->ns->href; } } -ContentNode::ContentNode(Node *pParent, xmlNode *plibNode) +ContentNode::ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode) : Node(IsContent, pParent, - plibNode, + pListAnchor, + pLibNode, NULL) { } @@ -1380,9 +1614,9 @@ Document::~Document() */ void Document::refreshInternals() // private { - m->pRootElement = new ElementNode(NULL, NULL, xmlDocGetRootElement(m->plibDocument)); + m->pRootElement = new ElementNode(NULL, NULL, NULL, xmlDocGetRootElement(m->plibDocument)); - m->pRootElement->buildChildren(*m->pRootElement); + ElementNode::buildChildren(m->pRootElement); } /** @@ -1390,7 +1624,7 @@ void Document::refreshInternals() // private * Const variant. * @return */ -const ElementNode* Document::getRootElement() const +const ElementNode *Document::getRootElement() const { return m->pRootElement; } @@ -1400,41 +1634,43 @@ const ElementNode* Document::getRootElement() const * Non-const variant. * @return */ -ElementNode* Document::getRootElement() +ElementNode *Document::getRootElement() { return m->pRootElement; } /** - * Creates a new element node and sets it as the root element. This will - * only work if the document is empty; otherwise EDocumentNotEmpty is thrown. + * Creates a new element node and sets it as the root element. + * + * This will only work if the document is empty; otherwise EDocumentNotEmpty is + * thrown. */ -ElementNode* Document::createRootElement(const char *pcszRootElementName, +ElementNode *Document::createRootElement(const char *pcszRootElementName, const char *pcszComment /* = NULL */) { if (m->pRootElement || m->plibDocument) throw EDocumentNotEmpty(RT_SRC_POS); // libxml side: create document, create root node - m->plibDocument = xmlNewDoc((const xmlChar*)"1.0"); - xmlNode *plibRootNode; - if (!(plibRootNode = xmlNewNode(NULL, // namespace - (const xmlChar*)pcszRootElementName))) + m->plibDocument = xmlNewDoc((const xmlChar *)"1.0"); + xmlNode *plibRootNode = xmlNewNode(NULL /*namespace*/ , (const xmlChar *)pcszRootElementName); + if (!plibRootNode) throw std::bad_alloc(); xmlDocSetRootElement(m->plibDocument, plibRootNode); + // now wrap this in C++ - m->pRootElement = new ElementNode(NULL, NULL, plibRootNode); + m->pRootElement = new ElementNode(NULL, NULL, NULL, plibRootNode); // add document global comment if specified if (pcszComment != NULL) { - xmlNode *pComment; - if (!(pComment = xmlNewDocComment(m->plibDocument, - (const xmlChar *)pcszComment))) + xmlNode *pComment = xmlNewDocComment(m->plibDocument, (const xmlChar *)pcszComment); + if (!pComment) throw std::bad_alloc(); xmlAddPrevSibling(plibRootNode, pComment); + // now wrap this in C++ - m->pComment = new ElementNode(NULL, NULL, pComment); + m->pComment = new ElementNode(NULL, NULL, NULL, pComment); } return m->pRootElement; @@ -1480,12 +1716,13 @@ XmlMemParser::~XmlMemParser() * * The document that is passed in will be reset before being filled if not empty. * - * @param pvBuf in: memory buffer to parse. - * @param cbSize in: size of the memory buffer. - * @param strFilename in: name fo file to parse. - * @param doc out: document to be reset and filled with data according to file contents. + * @param pvBuf Memory buffer to parse. + * @param cbSize Size of the memory buffer. + * @param strFilename Refernece to the name of the file we're parsing. + * @param doc Reference to the output document. This will be reset + * and filled with data according to file contents. */ -void XmlMemParser::read(const void* pvBuf, size_t cbSize, +void XmlMemParser::read(const void *pvBuf, size_t cbSize, const RTCString &strFilename, Document &doc) { |