Index: /trunk/include/iprt/dir.h
===================================================================
--- /trunk/include/iprt/dir.h	(revision 20110)
+++ /trunk/include/iprt/dir.h	(revision 20111)
@@ -76,10 +76,15 @@
 
 /**
- * Creates a new temporary directory with a unique name.
- *
- * It takes a path with a directory name template and overwrites a portion of it
- * to create the unique name. The template may be any directory name with one or
- * more tailing `X`. The trailing `Xs` will be replaced by alpha numeric
- * characters to create a directory unique name.
+ * Creates a new directory with a unique name using the given template.
+ *
+ * One or more trailing X'es in the template will be replaced by random alpha
+ * numeric characters until a RTDirCreate succeeds or we run out of patience.
+ * For instance:
+ *          "/tmp/myprog-XXXXXX"
+ *
+ * As an alternative to trailing X'es, it
+ * is possible to put 3 or more X'es somewhere inside the directory name. In
+ * the following string only the last bunch of X'es will be modified:
+ *          "/tmp/myprog-XXX-XXX.tmp"
  *
  * The directory is created with mode 0700.
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 20110)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 20111)
@@ -275,4 +275,5 @@
 	generic/critsect-generic.cpp \
 	generic/env-generic.cpp \
+	generic/RTDirCreateTemp-generic.cpp \
 	generic/RTFileCopy-generic.cpp \
 	generic/RTFileReadAll-generic.cpp \
Index: /trunk/src/VBox/Runtime/generic/RTDirCreateTemp-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTDirCreateTemp-generic.cpp	(revision 20110)
+++ /trunk/src/VBox/Runtime/generic/RTDirCreateTemp-generic.cpp	(revision 20111)
@@ -37,4 +37,5 @@
 #include <iprt/assert.h>
 #include <iprt/err.h>
+#include <iprt/path.h>
 #include <iprt/rand.h>
 #include <iprt/string.h>
@@ -44,14 +45,45 @@
 {
     /*
-     * Validate input.
+     * Validate input and count X'es.
+     *
+     * The X'es may be trailing, or they may be a cluster of 3 or more inside
+     * the file name.
      */
     AssertPtr(pszTemplate);
     unsigned    cXes = 0;
     char       *pszX = strchr(pszTemplate, '\0');
-    while (pszX != pszTemplate && pszX[-1] == 'X')
+    if (   pszX != pszTemplate
+        && pszX[-1] != 'X')
+    {
+        /* look inside the file name. */
+        char *pszFilename = RTPathFilename(pszTemplate);
+        if (   pszFilename
+            && (size_t)(pszX - pszFilename) > 3)
+        {
+            char *pszXEnd = pszX - 1;
+            pszFilename += 3;
+            do
+            {
+                if (    pszXEnd[-1] == 'X'
+                    &&  pszXEnd[-2] == 'X'
+                    &&  pszXEnd[-3] == 'X')
+                {
+                    pszX = pszXEnd - 3;
+                    cXes = 3;
+                    break;
+                }
+            } while (pszXEnd-- != pszFilename);
+        }
+    }
+
+    /* count them */
+    while (   pszX != pszTemplate
+           && pszX[-1] == 'X')
     {
         pszX--;
         cXes++;
     }
+
+    /* fail if none found. */
     if (!cXes)
     {
@@ -70,5 +102,5 @@
         unsigned j = cXes;
         while (j-- > 0)
-            pszX[j] = s_sz[RTRandU32Ex(0, RT_ELEMENTS(s_sz) - 1)];
+            pszX[j] = s_sz[RTRandU32Ex(0, RT_ELEMENTS(s_sz) - 2)];
         int rc = RTDirCreate(pszTemplate, 0700);
         if (RT_SUCCESS(rc))
Index: /trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp	(revision 20110)
+++ /trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp	(revision 20111)
@@ -107,13 +107,4 @@
     LogFlow(("RTDirCreate(%p={%s}, %RTfmode): returns %Rrc\n", pszPath, pszPath, fMode, rc));
     return rc;
-}
-
-
-RTDECL(int) RTDirCreateTemp(char *pszTemplate)
-{
-    if (mkdtemp(pszTemplate))
-        return VINF_SUCCESS;
-
-    return RTErrConvertFromErrno(errno);
 }
 
Index: /trunk/src/VBox/Runtime/r3/win/dir-win.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/dir-win.cpp	(revision 20110)
+++ /trunk/src/VBox/Runtime/r3/win/dir-win.cpp	(revision 20111)
@@ -129,17 +129,4 @@
 
 
-RTDECL(int) RTDirCreateTemp(char *pszTemplate)
-{
-    /** @todo r=bird: this doesn't work for more than 26 calls and it's racy:
-     *        http://msdn.microsoft.com/en-us/library/34wc6k1f(VS.80).aspx */
-    if (_mktemp(pszTemplate))
-    {
-        int rc = RTDirCreate(pszTemplate, 0700);
-        return rc;
-    }
-    return RTErrConvertFromErrno(errno);
-}
-
-
 RTDECL(int) RTDirRemove(const char *pszPath)
 {
Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 20110)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 20111)
@@ -89,4 +89,5 @@
 	tstStrToNum \
 	tstSystemQueryOsInfo \
+	tstRTTemp \
 	tstTermCallbacks \
 	tstThread-1 \
@@ -348,4 +349,7 @@
 tstSystemQueryOsInfo_SOURCES = tstSystemQueryOsInfo.cpp
 
+tstRTTemp_TEMPLATE = VBOXR3TSTEXE
+tstRTTemp_SOURCES = tstRTTemp.cpp
+
 tstTermCallbacks_SOURCES = tstTermCallbacks.cpp
 
Index: /trunk/src/VBox/Runtime/testcase/tstRTTemp.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTTemp.cpp	(revision 20111)
+++ /trunk/src/VBox/Runtime/testcase/tstRTTemp.cpp	(revision 20111)
@@ -0,0 +1,137 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - Temporary files and directories.
+ */
+
+/*
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
+
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static char g_szTempPath[RTPATH_MAX - 50];
+
+
+static void tstDirCreateTemp(const char *pszSubTest, const char *pszTemplate, unsigned cTimes, bool fSkipXCheck)
+{
+    RTTestISub(pszSubTest);
+
+    /* Allocate the result array. */
+    char **papszNames = (char **)RTMemTmpAllocZ(cTimes * sizeof(char *));
+    RTTESTI_CHECK_RETV(papszNames != NULL);
+
+    /* The test loop. */
+    unsigned i;
+    for (i = 0; i < cTimes; i++)
+    {
+        int rc;
+        char szName[RTPATH_MAX];
+        RTTESTI_CHECK_RC(rc = RTPathAppend(strcpy(szName, g_szTempPath), sizeof(szName), pszTemplate), VINF_SUCCESS);
+        if (RT_FAILURE(rc))
+            break;
+
+        RTTESTI_CHECK(papszNames[i] = RTStrDup(szName));
+        if (!papszNames[i])
+            break;
+
+        rc = RTDirCreateTemp(papszNames[i]);
+        if (rc != VINF_SUCCESS)
+        {
+            RTTestIFailed("RTDirCreateTemp(%s) call #%u -> %Rrc\n", szName, i, rc);
+            RTStrFree(papszNames[i]);
+            papszNames[i] = NULL;
+            break;
+        }
+        RTTestIPrintf(RTTESTLVL_DEBUG, "%s\n", papszNames[i]);
+        RTTESTI_CHECK_MSG(strlen(szName) == strlen(papszNames[i]), ("szName   %s\nReturned %s\n", szName, papszNames[i]));
+        if (!fSkipXCheck)
+            RTTESTI_CHECK_MSG(strchr(RTPathFilename(papszNames[i]), 'X') == NULL, ("szName   %s\nReturned %s\n", szName, papszNames[i]));
+    }
+
+    /* cleanup */
+    while (i-- > 0)
+    {
+        RTTESTI_CHECK_RC(RTDirRemove(papszNames[i]), VINF_SUCCESS);
+        RTStrFree(papszNames[i]);
+    }
+    RTMemTmpFree(papszNames);
+}
+
+
+int main()
+{
+    int rc = RTR3Init();
+    if (RT_FAILURE(rc))
+        return 1;
+    RTTEST hTest;
+    rc = RTTestCreate("tstRTTemp", &hTest);
+    if (RT_FAILURE(rc))
+        return 1;
+    RTTestBanner(hTest);
+
+    /*
+     * Get the temp directory (this is essential to the testcase).
+     */
+    RTTESTI_CHECK_RC(rc = RTPathTemp(g_szTempPath, sizeof(g_szTempPath)), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+
+    /*
+     * Create N temporary directories using RTDirCreateTemp.
+     */
+    tstDirCreateTemp("RTDirCreateTemp #1 (standard)",   "rtRTTemp-XXXXXX",              128, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #2 (long)",       "rtRTTemp-XXXXXXXXXXXXXXXXX",   128, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #3 (short)",      "rtRTTemp-XX",                  128, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #4 (very short)", "rtRTTemp-X",                 26+10, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #5 (in-name)",    "rtRTTemp-XXXt",                  2, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #6 (in-name)",    "XXX-rtRTTemp",                   2, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #7 (in-name)",    "rtRTTemp-XXXXXXXXX.tmp",       128, false /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #8 (in-name)",    "rtRTTemp-XXXXXXX-X.tmp",       128, true /*fSkipXCheck*/);
+    tstDirCreateTemp("RTDirCreateTemp #9 (in-name)",    "rtRTTemp-XXXXXX-XX.tmp",       128, true /*fSkipXCheck*/);
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
+
+
