RTDECL(int) RTDirCreateTemp(char *pszTemplate, RTFMODE fMode) { char *pszX = NULL; unsigned cXes = 0; int rc = rtCreateTempValidateTemplate(pszTemplate, &pszX, &cXes); if (RT_FAILURE(rc)) { *pszTemplate = '\0'; return rc; } /* * Try ten thousand times. */ int i = 10000; while (i-- > 0) { rtCreateTempFillTemplate(pszX, cXes); rc = RTDirCreate(pszTemplate, fMode, 0); if (RT_SUCCESS(rc)) return rc; if (rc != VERR_ALREADY_EXISTS) { *pszTemplate = '\0'; return rc; } } /* we've given up. */ *pszTemplate = '\0'; return VERR_ALREADY_EXISTS; }
int main(int argc, char *argv[]) { RTR3InitExe(argc, &argv, 0); int rc; RTPrintf("tstVD: TESTING...\n"); /* * Clean up potential leftovers from previous unsuccessful runs. */ RTFileDelete("tmpVDCreate.vdi"); if (!RTDirExists("tmp")) { rc = RTDirCreate("tmp", RTFS_UNIX_IRWXU, 0); if (RT_FAILURE(rc)) { RTPrintf("tstVD: Failed to create 'tmp' directory! rc=%Rrc\n", rc); g_cErrors++; } } #ifdef VDI_TEST rc = tstVDCreateShareDelete("VDI", "tmpVDCreate.vdi", 10 * _1M, VD_IMAGE_FLAGS_FIXED); if (RT_FAILURE(rc)) { RTPrintf("tstVD: VDI shareable test failed! rc=%Rrc\n", rc); g_cErrors++; } #endif /* VDI_TEST */ /* * Clean up any leftovers. */ RTFileDelete("tmpVDCreate.vdi"); rc = VDShutdown(); if (RT_FAILURE(rc)) { RTPrintf("tstVD: unloading backends failed! rc=%Rrc\n", rc); g_cErrors++; } /* * Summary */ if (!g_cErrors) RTPrintf("tstVD: SUCCESS\n"); else RTPrintf("tstVD: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; }
RTDECL(int) RTDirCreateFullPath(const char *pszPath, RTFMODE fMode) { /* * Resolve the path. */ char szAbsPath[RTPATH_MAX]; int rc = RTPathAbs(pszPath, szAbsPath, sizeof(szAbsPath)); if (RT_FAILURE(rc)) return rc; /* * Iterate the path components making sure each of them exists. */ /* skip volume name */ char *psz = &szAbsPath[rtPathVolumeSpecLen(szAbsPath)]; /* skip the root slash if any */ if ( psz[0] == '/' #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) || psz[0] == '\\' #endif ) psz++; /* iterate over path components. */ do { /* the next component is NULL, stop iterating */ if (!*psz) break; #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) psz = strpbrk(psz, "\\/"); #else psz = strchr(psz, '/'); #endif if (psz) *psz = '\0'; /* * ASSUME that RTDirCreate will return VERR_ALREADY_EXISTS and not VERR_ACCESS_DENIED in those cases * where the directory exists but we don't have write access to the parent directory. */ rc = RTDirCreate(szAbsPath, fMode, 0); if (rc == VERR_ALREADY_EXISTS) rc = VINF_SUCCESS; if (!psz) break; *psz++ = RTPATH_DELIMITER; } while (RT_SUCCESS(rc)); return rc; }
/** * Adds a file to the cache. * * @returns IPRT status code. * @param pszSrcPath Path to the source file. * @param pszDstName The name of the destionation file (no path stuff). * @param pszExtraSuff Optional extra suffix. Mach-O dSYM hack. * @param pszDstSubDir The subdirectory to file it under. This is the * stringification of a relatively unique identifier of * the file in question. * @param pAddToUuidMap Optional file UUID that is used to create a UUID map * entry. * @param pszUuidMapDir The UUID map subdirectory in the cache, if this is * wanted, otherwise NULL. * @param pCfg The configuration. */ static int rtDbgSymCacheAddOneFile(const char *pszSrcPath, const char *pszDstName, const char *pszExtraStuff, const char *pszDstSubDir, PRTUUID pAddToUuidMap, const char *pszUuidMapDir, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Build and create the destination path, step by step. */ char szDstPath[RTPATH_MAX]; int rc = RTPathJoin(szDstPath, sizeof(szDstPath), pCfg->pszCache, pszDstName); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); if (!RTDirExists(szDstPath)) { rc = RTDirCreate(szDstPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error creating '%s': %Rrc", szDstPath, rc); } rc = RTPathAppend(szDstPath, sizeof(szDstPath), pszDstSubDir); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); if (!RTDirExists(szDstPath)) { rc = RTDirCreate(szDstPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error creating '%s': %Rrc", szDstPath, rc); } rc = RTPathAppend(szDstPath, sizeof(szDstPath), pszDstName); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); if (pszExtraStuff) { rc = RTStrCat(szDstPath, sizeof(szDstPath), pszExtraStuff); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); } /* * If the file exists, we compare the two and throws an error if the doesn't match. */ if (RTPathExists(szDstPath)) { rc = RTFileCompare(pszSrcPath, szDstPath); if (RT_SUCCESS(rc)) { RTMsgInfo("%s is already in the cache.", pszSrcPath); if (pAddToUuidMap && pszUuidMapDir) return rtDbgSymCacheAddCreateUuidMapping(szDstPath, pAddToUuidMap, pszUuidMapDir, pCfg); return VINF_SUCCESS; } if (rc == VERR_NOT_EQUAL) RTMsgInfo("Cache conflict with existing entry '%s' when inserting '%s'.", szDstPath, pszSrcPath); else RTMsgInfo("Error comparing '%s' with '%s': %Rrc", pszSrcPath, szDstPath, rc); if (!pCfg->fOverwriteOnConflict) return rc; } /* * The file doesn't exist or we should overwrite it, */ RTMsgInfo("Copying '%s' to '%s'...", pszSrcPath, szDstPath); rc = RTFileCopy(pszSrcPath, szDstPath); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error copying '%s' to '%s': %Rrc", pszSrcPath, szDstPath, rc); if (pAddToUuidMap && pszUuidMapDir) return rtDbgSymCacheAddCreateUuidMapping(szDstPath, pAddToUuidMap, pszUuidMapDir, pCfg); return VINF_SUCCESS; }
/** * Creates a UUID mapping for the file. * * @returns IPRT status code. * @param pszCacheFile The path to the file in the cache. * @param pFileUuid The UUID of the file. * @param pszUuidMapDir The UUID map subdirectory in the cache, if this is * wanted, otherwise NULL. * @param pCfg The configuration. */ static int rtDbgSymCacheAddCreateUuidMapping(const char *pszCacheFile, PRTUUID pFileUuid, const char *pszUuidMapDir, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Create the UUID map entry first, deep. */ char szMapPath[RTPATH_MAX]; int rc = RTPathJoin(szMapPath, sizeof(szMapPath) - sizeof("/xxxx/yyyy/xxxx/yyyy/xxxx/zzzzzzzzzzzz") + 1, pCfg->pszCache, pszUuidMapDir); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing UUID map path (RTPathJoin): %Rrc", rc); size_t cch = strlen(szMapPath); szMapPath[cch] = '-'; rc = RTUuidToStr(pFileUuid, &szMapPath[cch + 2], sizeof(szMapPath) - cch); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing UUID map path (RTUuidToStr): %Rrc", rc); /* Uppercase the whole lot. */ RTStrToUpper(&szMapPath[cch + 2]); /* Split the first dword in two. */ szMapPath[cch + 1] = szMapPath[cch + 2]; szMapPath[cch + 2] = szMapPath[cch + 3]; szMapPath[cch + 3] = szMapPath[cch + 4]; szMapPath[cch + 4] = szMapPath[cch + 5]; szMapPath[cch + 5] = '-'; /* * Create the directories in the path. */ char chSaved = RTPATH_SLASH; for (unsigned i = 0; i < 6; i++, cch += 5) { Assert(szMapPath[cch] == '-'); szMapPath[cch] = '\0'; if (!RTDirExists(szMapPath)) { rc = RTDirCreate(szMapPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "RTDirCreate failed on '%s' (UUID map path): %Rrc", szMapPath, rc); } szMapPath[cch] = RTPATH_SLASH; } cch -= 5; /* * Calculate a relative path from there to the actual file. */ char szLinkTarget[RTPATH_MAX]; //szMapPath[cch] = '\0'; rc = RTPathCalcRelative(szLinkTarget, sizeof(szLinkTarget), szMapPath, pszCacheFile); //szMapPath[cch] = RTPATH_SLASH; if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Failed to calculate relative path from '%s' to '%s': %Rrc", szMapPath, pszCacheFile, rc); /* * If there is already a link there, check if it matches or whether * perhaps it's target doesn't exist. */ RTFSOBJINFO ObjInfo; rc = RTPathQueryInfoEx(szMapPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); if (RT_SUCCESS(rc)) { if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) { rc = RTPathQueryInfoEx(szMapPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK); if (RT_SUCCESS(rc)) { char *pszCurTarget = NULL; rc = RTSymlinkReadA(szMapPath, &pszCurTarget); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "UUID map: failed to read existing symlink '%s': %Rrc", szMapPath, rc); if (RTPathCompare(pszCurTarget, szLinkTarget) == 0) RTMsgInfo("UUID map: existing link '%s' has the same target ('%s').", szMapPath, pszCurTarget); else { RTMsgError("UUID map: Existing mapping '%s' pointing to '%s' insted of '%s'", szMapPath, pszCurTarget, szLinkTarget); rc = VERR_ALREADY_EXISTS; } RTStrFree(pszCurTarget); return rc; } else RTMsgInfo("UUID map: replacing dangling link '%s'", szMapPath); RTSymlinkDelete(szMapPath, 0 /*fFlags*/); } else if (RTFS_IS_FILE(ObjInfo.Attr.fMode)) return RTMsgErrorRc(VERR_IS_A_FILE, "UUID map: found file at '%s', expect symbolic link or nothing.", szMapPath); else if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)) return RTMsgErrorRc(VERR_IS_A_DIRECTORY, "UUID map: found directory at '%s', expect symbolic link or nothing.", szMapPath); else return RTMsgErrorRc(VERR_NOT_SYMLINK, "UUID map: Expected symbolic link or nothing at '%s', found: fMode=%#x", szMapPath, ObjInfo.Attr.fMode); } /* * Create the symbolic link. */ rc = RTSymlinkCreate(szMapPath, szLinkTarget, RTSYMLINKTYPE_FILE, 0); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Failed to create UUID map symlink '%s' to '%s': %Rrc", szMapPath, szLinkTarget, rc); RTMsgInfo("UUID map: %s => %s", szMapPath, szLinkTarget); return VINF_SUCCESS; }
/** * Handles the 'add' command. * * @returns Program exit code. * @param pszArg0 The program name. * @param cArgs The number of arguments to the 'add' command. * @param papszArgs The argument vector, starting after 'add'. */ static RTEXITCODE rtDbgSymCacheCmdAdd(const char *pszArg0, int cArgs, char **papszArgs) { /* * Parse the command line. */ static RTGETOPTDEF const s_aOptions[] = { { "--recursive", 'R', RTGETOPT_REQ_NOTHING }, { "--no-recursive", 'n', RTGETOPT_REQ_NOTHING }, { "--overwrite-on-conflict", 'o', RTGETOPT_REQ_NOTHING }, }; const char *pszCache = NULL; bool fRecursive = false; bool fOverwriteOnConflict = false; RTGETOPTSTATE State; int rc = RTGetOptInit(&State, cArgs, papszArgs, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc", rc); uint32_t cAdded = 0; RTGETOPTUNION ValueUnion; int chOpt; while ((chOpt = RTGetOpt(&State, &ValueUnion)) != 0) { switch (chOpt) { case 'R': fRecursive = true; break; case 'n': fRecursive = false; break; case 'o': fOverwriteOnConflict = true; break; case VINF_GETOPT_NOT_OPTION: /* The first non-option is a cache directory. */ if (!pszCache) { pszCache = ValueUnion.psz; if (!RTPathExists(pszCache)) { rc = RTDirCreate(pszCache, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Error creating cache directory '%s': %Rrc", pszCache, rc); } else if (!RTDirExists(pszCache)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Specified cache directory is not a directory: '%s'", pszCache); } /* Subsequent non-options are files to be added to the cache. */ else { RTEXITCODE rcExit = rtDbgSymCacheAddFileOrDir(ValueUnion.psz, pszCache, fRecursive, fOverwriteOnConflict); if (rcExit != RTEXITCODE_FAILURE) return rcExit; } break; case 'h': return rtDbgSymCacheUsage(pszArg0, "add"); case 'V': return rtDbgSymCacheVersion(); default: return RTGetOptPrintError(chOpt, &ValueUnion); } } if (!pszCache) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No cache directory or files to add were specified."); return RTEXITCODE_SUCCESS; }
static int vbglR3DnDHGProcessURIMessages(uint32_t uClientId, uint32_t *puScreenId, char *pszFormat, uint32_t cbFormat, uint32_t *pcbFormatRecv, void **ppvData, uint32_t cbData, size_t *pcbDataRecv) { /* Make a string list out of the uri data. */ RTCList<RTCString> uriList = RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n"); if (uriList.isEmpty()) return VINF_SUCCESS; uint32_t cbTmpData = _1M * 10; void *pvTmpData = RTMemAlloc(cbTmpData); if (!pvTmpData) return VERR_NO_MEMORY; /* Create and query the drop target directory. */ char pszDropDir[RTPATH_MAX]; int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir)); if (RT_FAILURE(rc)) { RTMemFree(pvTmpData); return rc; } /* Patch the old drop data with the new drop directory, so the drop target * can find the files. */ RTCList<RTCString> guestUriList; for (size_t i = 0; i < uriList.size(); ++i) { const RTCString &strUri = uriList.at(i); /* Query the path component of a file URI. If this hasn't a * file scheme, null is returned. */ if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO)) { RTCString strFullPath = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath); char *pszNewUri = RTUriFileCreate(strFullPath.c_str()); if (pszNewUri) { guestUriList.append(pszNewUri); RTStrFree(pszNewUri); } } else guestUriList.append(strUri); } /* Cleanup the old data and write the new data back to the event. */ RTMemFree(*ppvData); RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n"; *ppvData = RTStrDupN(newData.c_str(), newData.length()); *pcbDataRecv = newData.length() + 1; /* Lists for holding created files & directories in the case of a * rollback. */ RTCList<RTCString> guestDirList; RTCList<RTCString> guestFileList; char pszPathname[RTPATH_MAX]; uint32_t cbPathname = 0; bool fLoop = true; do { uint32_t uNextMsg; uint32_t cNextParms; rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false); DO(("%Rrc - %d\n", rc , uNextMsg)); if (RT_SUCCESS(rc)) { switch(uNextMsg) { case DragAndDropSvc::HOST_DND_HG_SND_DIR: { uint32_t fMode = 0; rc = vbglR3DnDHGProcessSendDirMessage(uClientId, pszPathname, sizeof(pszPathname), &cbPathname, &fMode); if (RT_SUCCESS(rc)) { DO(("Got drop dir: %s - %o - %Rrc\n", pszPathname, fMode, rc)); char *pszNewDir = RTPathJoinA(pszDropDir, pszPathname); rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0); if (!guestDirList.contains(pszNewDir)) guestDirList.append(pszNewDir); } break; } case DragAndDropSvc::HOST_DND_HG_SND_FILE: { uint32_t cbDataRecv; uint32_t fMode = 0; rc = vbglR3DnDHGProcessSendFileMessage(uClientId, pszPathname, sizeof(pszPathname), &cbPathname, pvTmpData, cbTmpData, &cbDataRecv, &fMode); if (RT_SUCCESS(rc)) { char *pszNewFile = RTPathJoinA(pszDropDir, pszPathname); DO(("Got drop file: %s - %d - %o - %Rrc\n", pszPathname, cbDataRecv, fMode, rc)); RTFILE hFile; rc = RTFileOpen(&hFile, pszNewFile, RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE); if (RT_SUCCESS(rc)) { rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL); if (RT_SUCCESS(rc)) { rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0); /* Valid UNIX mode? */ if ( RT_SUCCESS(rc) && (fMode & RTFS_UNIX_MASK)) rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); } RTFileClose(hFile); if (!guestFileList.contains(pszNewFile)) guestFileList.append(pszNewFile); } } break; } case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL: { rc = vbglR3DnDHGProcessCancelMessage(uClientId); if (RT_SUCCESS(rc)) rc = VERR_CANCELLED; /* Break out of the loop. */ } default: fLoop = false; break; } } else { if (rc == VERR_NO_DATA) rc = VINF_SUCCESS; break; } }while(fLoop); RTMemFree(pvTmpData); /* Cleanup on failure or if the user has canceled. */ if (RT_FAILURE(rc)) { /* Remove any stuff created. */ for (size_t i = 0; i < guestFileList.size(); ++i) RTFileDelete(guestFileList.at(i).c_str()); for (size_t i = 0; i < guestDirList.size(); ++i) RTDirRemove(guestDirList.at(i).c_str()); RTDirRemove(pszDropDir); } return rc; }
RTDECL(int) RTDirCreateTemp(char *pszTemplate) { /* * 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'); 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) { AssertFailed(); *pszTemplate = '\0'; return VERR_INVALID_PARAMETER; } /* * Try ten thousand times. */ int i = 10000; while (i-- > 0) { static char const s_sz[] = "0123456789abcdefghijklmnopqrstuvwxyz"; unsigned j = cXes; while (j-- > 0) pszX[j] = s_sz[RTRandU32Ex(0, RT_ELEMENTS(s_sz) - 2)]; int rc = RTDirCreate(pszTemplate, 0700); if (RT_SUCCESS(rc)) return rc; if (rc != VERR_ALREADY_EXISTS) { *pszTemplate = '\0'; return rc; } } /* we've given up. */ *pszTemplate = '\0'; return VERR_ALREADY_EXISTS; }
RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, signed int cchDigits, char chSep) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(cbSize, VERR_BUFFER_OVERFLOW); AssertReturn(cchDigits > 0, VERR_INVALID_PARAMETER); /* Check that there is sufficient space. */ char *pszEnd = RTStrEnd(pszPath, cbSize); AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW); AssertReturn(cbSize - 1 - (pszEnd - pszPath) >= (size_t)cchDigits + (chSep ? 1 : 0), VERR_BUFFER_OVERFLOW); size_t cbLeft = cbSize - (pszEnd - pszPath); /* First try is to create the path without any numbers. */ int rc = RTDirCreate(pszPath, fMode, 0); if ( RT_SUCCESS(rc) || rc != VERR_ALREADY_EXISTS) return rc; /* If the separator value isn't zero, add it. */ if (chSep != '\0') { cbLeft--; *pszEnd++ = chSep; *pszEnd = '\0'; } /* How many tries? Stay within somewhat sane limits. */ uint32_t cMaxTries; if (cchDigits >= 8) cMaxTries = 100 * _1M; else { cMaxTries = 10; for (int a = 0; a < cchDigits - 1; ++a) cMaxTries *= 10; } /* Try cMaxTries - 1 times to create a directory with appended numbers. */ uint32_t i = 1; while (i < cMaxTries) { /* Format the number with leading zero's. */ ssize_t rc2 = RTStrFormatU32(pszEnd, cbLeft, i, 10, cchDigits, 0, RTSTR_F_WIDTH | RTSTR_F_ZEROPAD); if (RT_FAILURE((int) rc2)) { *pszPath = '\0'; return (int)rc2; } rc = RTDirCreate(pszPath, fMode, 0); if (RT_SUCCESS(rc)) return rc; ++i; } /* We've given up. */ *pszPath = '\0'; return VERR_ALREADY_EXISTS; }