Changeset 15754 in vbox for trunk/src/VBox
- Timestamp:
- Dec 25, 2008 10:52:24 AM (16 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/posix/path-posix.cpp
r14054 r15754 169 169 RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath) 170 170 { 171 /* 172 * Convert input. 173 */ 174 char *pszNativePath; 175 int rc = rtPathToNative(&pszNativePath, pszPath); 176 if (RT_FAILURE(rc)) 171 if (strlen(pszPath) > PATH_MAX) 177 172 { 178 173 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, 179 pszPath, pszAbsPath, cchAbsPath, rc)); 180 return rc; 181 } 182 183 /* 184 * On POSIX platforms the API doesn't take a length parameter, which makes it 185 * a little bit more work. 186 */ 174 pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG)); 175 return VERR_FILENAME_TOO_LONG; 176 } 177 187 178 char szTmpPath[PATH_MAX + 1]; 188 char *psz = realpath(pszNativePath, szTmpPath); 189 if (!psz) 190 { 191 if (errno == ENOENT || errno == ENOTDIR 192 #ifdef RT_OS_OS2 193 /// @todo realpath() returns EIO for non-existent UNC paths like 194 // //server/share/subdir (i.e. when a subdir is specified within 195 // a share). We should either fix realpath() in libc or remove 196 // this todo. 197 || errno == EIO 198 #endif 199 ) 200 { 201 if (strlen(pszNativePath) <= PATH_MAX) 202 { 203 /* 204 * Iterate the path bit by bit an apply realpath to it. 205 */ 206 207 char szTmpSrc[PATH_MAX + 1]; 208 strcpy(szTmpSrc, pszNativePath); 209 fsCleanPath(szTmpSrc); 210 211 size_t cch = 0; // current resolved path length 212 char *pszCur = szTmpSrc; 179 strcpy(szTmpPath, pszPath); 180 fsCleanPath(szTmpPath); 181 182 char *pszCur = szTmpPath; 213 183 214 184 #ifdef HAVE_DRIVE 215 if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/') 216 { 217 psz = szTmpPath; 218 cch = 2; 219 pszCur += 3; 220 } 185 if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/') 186 pszCur += 3; 221 187 #ifdef HAVE_UNC 222 else 223 if (pszCur[0] == '/' && pszCur[1] == '/') 224 { 225 pszCur += 2; 226 char *pszSlash = strchr(pszCur, '/'); 227 size_t cchElement = pszSlash ? pszSlash - pszCur : strlen(pszCur); 228 if (cchElement && pszCur[cchElement]) 229 { 230 psz = szTmpPath; 231 cch = cchElement + 2; 232 pszCur += cchElement + 1; 233 } 234 else 235 /* we've got just "//server" or "//" */ 236 /// @todo (r=dmik) not 100% sure we should fail, but the 237 // above cases are just invalid (incomplete) paths, 238 // no matter that Win32 returns these paths as is. 239 rc = VERR_INVALID_NAME; 240 } 188 else 189 if (pszCur[0] == '/' && pszCur[1] == '/') 190 pszCur += 2; 241 191 #endif 242 192 #else 243 if (*pszCur == '/') 244 { 245 psz = szTmpPath; 246 pszCur++; 247 } 193 if (pszCur[0] == '/') 194 pszCur += 1; 248 195 #endif 249 else 250 { 251 /* get the cwd */ 252 psz = getcwd(szTmpPath, sizeof(szTmpPath)); 253 AssertMsg(psz, ("Couldn't get cwd!\n")); 254 if (psz) 255 { 256 #ifdef HAVE_DRIVE 257 if (*pszCur == '/') 258 { 259 cch = 2; 260 pszCur++; 261 } 262 else 263 #endif 264 cch = strlen(psz); 265 } 266 else 267 rc = RTErrConvertFromErrno(errno); 268 } 269 270 if (psz) 271 { 272 bool fResolveSymlinks = true; 273 char szTmpPath2[PATH_MAX + 1]; 274 275 /* make sure strrchr() will work correctly */ 276 psz[cch] = '\0'; 277 278 while (*pszCur) 279 { 280 char *pszSlash = strchr(pszCur, '/'); 281 size_t cchElement = pszSlash ? pszSlash - pszCur : strlen(pszCur); 282 if (cch + cchElement + 1 > PATH_MAX) 283 { 284 rc = VERR_FILENAME_TOO_LONG; 285 break; 286 } 287 288 if (!strncmp(pszCur, "..", cchElement)) 289 { 290 char *pszLastSlash = strrchr(psz, '/'); 291 #ifdef HAVE_UNC 292 if (pszLastSlash && pszLastSlash > psz && 293 pszLastSlash[-1] != '/') 294 #else 295 if (pszLastSlash) 296 #endif 297 { 298 cch = pszLastSlash - psz; 299 psz[cch] = '\0'; 300 } 301 /* else: We've reached the root and the parent of 302 * the root is the root. */ 303 } 304 else 305 { 306 psz[cch++] = '/'; 307 memcpy(psz + cch, pszCur, cchElement); 308 cch += cchElement; 309 psz[cch] = '\0'; 310 311 if (fResolveSymlinks) 312 { 313 /* resolve possible symlinks */ 314 char *psz2 = realpath(psz, psz == szTmpPath 315 ? szTmpPath2 316 : szTmpPath); 317 if (psz2) 318 { 319 psz = psz2; 320 cch = strlen(psz); 321 } 322 else 323 { 324 if (errno != ENOENT && errno != ENOTDIR 325 #ifdef RT_OS_OS2 326 /// @todo see above 327 && errno != EIO 328 #endif 329 ) 330 { 331 rc = RTErrConvertFromErrno(errno); 332 break; 333 } 334 335 /* no more need to resolve symlinks */ 336 fResolveSymlinks = false; 337 } 338 } 339 } 340 341 pszCur += cchElement; 342 /* skip the slash */ 343 if (*pszCur) 344 ++pszCur; 345 } 346 347 #ifdef HAVE_DRIVE 348 /* check if we're at the root */ 349 if (cch == 2 && RTPATH_IS_VOLSEP(psz[1])) 350 #else 351 /* if the length is zero here, then we're at the root */ 352 if (!cch) 353 #endif 354 { 355 psz[cch++] = '/'; 356 psz[cch] = '\0'; 357 } 358 } 359 } 360 else 361 rc = VERR_FILENAME_TOO_LONG; 362 } 363 else 364 rc = RTErrConvertFromErrno(errno); 365 } 366 367 RTStrFree(pszNativePath); 368 369 if (psz && RT_SUCCESS(rc)) 196 else 370 197 { 371 198 /* 372 * Convert result and copy it to the return buffer.199 * Prepend the current directory to the relative path. 373 200 */ 374 char *pszUtf8AbsPath; 375 rc = rtPathFromNative(&pszUtf8AbsPath, psz); 376 if (RT_FAILURE(rc)) 377 { 201 202 char szCurDir[PATH_MAX + 1]; 203 if (getcwd(szCurDir, sizeof(szCurDir)) == NULL) 204 { 205 AssertMsgFailed(("Couldn't get cwd!\n")); 206 207 int rc = RTErrConvertFromErrno(errno); 378 208 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, 379 209 pszPath, pszAbsPath, cchAbsPath, rc)); … … 381 211 } 382 212 383 /* replace '/' back with native RTPATH_SLASH */ 384 psz = pszUtf8AbsPath; 385 for (; *psz; psz++) 386 if (*psz == '/') 387 *psz = RTPATH_SLASH; 388 389 unsigned cch = strlen(pszUtf8AbsPath) + 1; 390 if (cch <= cchAbsPath) 391 memcpy(pszAbsPath, pszUtf8AbsPath, cch); 213 fsCleanPath(szCurDir); 214 215 { 216 /* 217 * Convert result and copy it to the return buffer. 218 */ 219 char *pszUtf8CurDir; 220 int rc = rtPathFromNative(&pszUtf8CurDir, szCurDir); 221 if (RT_FAILURE(rc)) 222 { 223 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, 224 pszPath, pszAbsPath, cchAbsPath, rc)); 225 return rc; 226 } 227 228 size_t cchUtf8CurDir = strlen(pszUtf8CurDir); 229 if (cchUtf8CurDir + strlen(szTmpPath) + 1 > PATH_MAX) 230 { 231 RTStrFree(pszUtf8CurDir); 232 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, 233 pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG)); 234 return VERR_FILENAME_TOO_LONG; 235 } 236 237 strcpy(szTmpPath + cchUtf8CurDir + 1, szTmpPath); 238 strcpy(szTmpPath, pszUtf8CurDir); 239 szTmpPath[cchUtf8CurDir] = '/'; 240 241 RTStrFree(pszUtf8CurDir); 242 } 243 244 #ifdef HAVE_DRIVE 245 if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/') 246 pszCur += 3; 247 #ifdef HAVE_UNC 392 248 else 393 rc = VERR_BUFFER_OVERFLOW; 394 RTStrFree(pszUtf8AbsPath); 395 } 249 if (pszCur[0] == '/' && pszCur[1] == '/') 250 pszCur += 2; 251 #endif 252 #else 253 if (pszCur[0] == '/') 254 pszCur += 1; 255 #endif 256 else 257 { 258 AssertFailed(); 259 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, 260 pszPath, pszAbsPath, cchAbsPath, VERR_GENERAL_FAILURE)); 261 return VERR_GENERAL_FAILURE; 262 } 263 } 264 265 char *pszTop = pszCur; 266 267 /* 268 * Get rid of double dot path components by evaluating them. 269 */ 270 271 for (;;) 272 { 273 if (pszCur[0] == '.' && pszCur[1] == '.' && 274 (!pszCur[2] || pszCur[2] == '/')) 275 { 276 /* rewind to the previous component if any */ 277 char *pszPrev = pszCur - 1; 278 if (pszPrev > pszTop) 279 while (*--pszPrev != '/') 280 ; 281 282 AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", 283 szTmpPath, pszPrev - szTmpPath)); 284 strcpy(pszPrev, pszCur + 2); 285 286 pszCur = pszPrev; 287 } 288 else 289 { 290 while (*pszCur && *pszCur != '/') 291 ++pszCur; 292 } 293 294 if (!*pszCur) 295 break; 296 297 /* skip the slash */ 298 ++pszCur; 299 } 300 301 if (pszCur < pszTop) 302 { 303 /* 304 * We overwrote the trailing slash of the root path with zero, restore 305 * it. 306 */ 307 *pszCur++ = '/'; 308 *pszCur = '\0'; 309 } 310 else if (pszCur > pszTop && *(pszCur - 1) == '/') 311 { 312 /* 313 * Extra trailing slash in a non-root path, remove it. 314 */ 315 *--pszCur = '\0'; 316 } 317 318 int rc = VINF_SUCCESS; 319 320 size_t cch = pszCur - szTmpPath + 1; 321 if (cch <= cchAbsPath) 322 memcpy(pszAbsPath, szTmpPath, cch); 323 else 324 rc = VERR_BUFFER_OVERFLOW; 396 325 397 326 LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, -
trunk/src/VBox/Runtime/testcase/tstPath.cpp
r14324 r15754 40 40 #include <iprt/param.h> 41 41 42 #if defined (RT_OS_WINDOWS) 43 # include <direct.h> // for getcwd 44 #else 45 # include <unistd.h> // for getcwd 46 #endif 47 #include <errno.h> // for getcwd 42 48 43 49 #define CHECK_RC(method) \ … … 85 91 */ 86 92 RTPrintf("tstPath: TESTING RTPathAbsEx()\n"); 87 static const char *aInput[] = 88 { 89 // NULL, NULL, -- assertion in RTStrToUtf16 90 NULL, "/absolute/..", 91 NULL, "/absolute\\\\../..", 92 NULL, "/absolute//../path", 93 NULL, "/absolute/../../path", 94 NULL, "relative/../dir\\.\\.\\.\\file.txt", 95 NULL, "\\", 96 "relative_base/dir\\", "\\from_root", 97 "relative_base/dir/", "relative_also", 98 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 99 NULL, "C:\\", 100 "C:\\", "..", 101 "C:\\temp", "..", 102 "C:\\VirtualBox/Machines", "..\\VirtualBox.xml", 103 "C:\\MustDie", "\\from_root/dir/..", 104 "C:\\temp", "D:\\data", 105 NULL, "\\\\server\\../share", // -- on Win32, GetFullPathName doesn't remove .. here 106 /* the three below use cases should fail with VERR_INVALID_NAME */ 107 //NULL, "\\\\server", 108 //NULL, "\\\\", 109 //NULL, "\\\\\\something", 110 "\\\\server\\share_as_base", "/from_root", 111 "\\\\just_server", "/from_root", 112 "\\\\server\\share_as_base", "relative\\data", 113 "base", "\\\\?\\UNC\\relative/edwef/..", 114 "base", "\\\\?\\UNC\\relative/edwef/..", 115 /* this is not (and I guess should not be) supported, should fail */ 116 ///@todo "\\\\?\\UNC\\base", "/from_root", 93 static const struct 94 { 95 const char *pcszInputBase; 96 const char *pcszInputPath; 97 int rc; 98 const char *pcszOutput; 99 } 100 aRTPathAbsExTests[] = 101 { 102 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 103 // { NULL, "", VINF_SUCCESS, "%p" }, 104 // { NULL, ".", VINF_SUCCESS, "%p" }, 105 { NULL, "\\", VINF_SUCCESS, "%d\\" }, 106 { NULL, "\\..", VINF_SUCCESS, "%d\\" }, 107 { NULL, "/absolute/..", VINF_SUCCESS, "%d\\" }, 108 { NULL, "/absolute\\\\../..", VINF_SUCCESS, "%d\\" }, 109 { NULL, "/absolute//../path\\", VINF_SUCCESS, "%d\\path" }, 110 { NULL, "/absolute/../../path", VINF_SUCCESS, "%d\\path" }, 111 { NULL, "relative/../dir\\.\\.\\.\\file.txt", VINF_SUCCESS, "%p\\dir\\file.txt" }, 112 { NULL, "\\data\\", VINF_SUCCESS, "%d\\data" }, 113 { "relative_base/dir\\", "\\from_root", VINF_SUCCESS, "%d\\from_root" }, 114 { "relative_base/dir/", "relative_also", VINF_SUCCESS, "%p\\relative_base\\dir\\relative_also" }, 117 115 #else 118 "\\temp", "..", 119 "\\VirtualBox/Machines", "..\\VirtualBox.xml", 120 "\\MustDie", "\\from_root/dir/..", 121 "\\temp", "\\data", 116 // { NULL, "", VINF_SUCCESS, "/" }, 117 // { NULL, ".", VINF_SUCCESS, "%p" }, 118 { NULL, "/", VINF_SUCCESS, "/" }, 119 { NULL, "/..", VINF_SUCCESS, "/" }, 120 { NULL, "/absolute/..", VINF_SUCCESS, "/" }, 121 { NULL, "/absolute\\\\../..", VINF_SUCCESS, "/" }, 122 { NULL, "/absolute//../path/", VINF_SUCCESS, "/path" }, 123 { NULL, "/absolute/../../path", VINF_SUCCESS, "/path" }, 124 { NULL, "relative/../dir/./././file.txt", VINF_SUCCESS, "%p/dir/file.txt" }, 125 { NULL, "relative/../dir\\.\\.\\.\\file.txt", VINF_SUCCESS, "%p/dir\\.\\.\\.\\file.txt" }, /* linux-specific */ 126 { NULL, "/data/", VINF_SUCCESS, "/data" }, 127 { "relative_base/dir/", "/from_root", VINF_SUCCESS, "/from_root" }, 128 { "relative_base/dir/", "relative_also", VINF_SUCCESS, "%p/relative_base/dir/relative_also" }, 129 #endif 130 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 131 { NULL, "C:\\", VINF_SUCCESS, "C:\\" }, 132 { "C:\\", "..", VINF_SUCCESS, "C:\\" }, 133 { "C:\\temp", "..", VINF_SUCCESS, "C:\\" }, 134 { "C:\\VirtualBox/Machines", "..\\VirtualBox.xml", VINF_SUCCESS, "C:\\VirtualBox\\VirtualBox.xml" }, 135 { "C:\\MustDie", "\\from_root/dir/..", VINF_SUCCESS, "C:\\from_root" }, 136 { "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" }, 137 { NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ }, 138 { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server" }, 139 { NULL, "\\\\", VINF_SUCCESS, "\\\\" }, 140 { NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ }, 141 { "\\\\server\\share_as_base", "/from_root", VINF_SUCCESS, "\\\\server\\from_root" }, 142 { "\\\\just_server", "/from_root", VINF_SUCCESS, "\\\\just_server\\from_root" }, 143 { "\\\\server\\share_as_base", "relative\\data", VINF_SUCCESS, "\\\\server\\share_as_base\\relative\\data" }, 144 { "base", "\\\\?\\UNC\\relative/edwef/..", VINF_SUCCESS, "\\\\?\\UNC\\relative" }, 145 { "\\\\?\\UNC\\base", "/from_root", VERR_INVALID_NAME, NULL }, 146 #else 147 { "/temp", "..", VINF_SUCCESS, "/" }, 148 { "/VirtualBox/Machines", "../VirtualBox.xml", VINF_SUCCESS, "/VirtualBox/VirtualBox.xml" }, 149 { "/MustDie", "/from_root/dir/..", VINF_SUCCESS, "/from_root" }, 150 { "\\temp", "\\data", VINF_SUCCESS, "%p/\\temp/\\data" }, 122 151 #endif 123 152 }; 124 153 125 for (unsigned i = 0; i < RT_ELEMENTS(aInput); i += 2) 126 { 127 RTPrintf("tstPath: base={%s}, path={%s}, ", aInput[i], aInput[i + 1]); 128 CHECK_RC(RTPathAbsEx(aInput[i], aInput[i + 1], szPath, sizeof(szPath))); 129 if (RT_SUCCESS(rc)) 130 RTPrintf("abs={%s}\n", szPath); 154 for (unsigned i = 0; i < RT_ELEMENTS(aRTPathAbsExTests); ++ i) 155 { 156 rc = RTPathAbsEx(aRTPathAbsExTests[i].pcszInputBase, 157 aRTPathAbsExTests[i].pcszInputPath, 158 szPath, sizeof(szPath)); 159 if (rc != aRTPathAbsExTests[i].rc) 160 { 161 RTPrintf("tstPath: RTPathAbsEx unexpected result code!\n" 162 " input base: '%s'\n" 163 " input path: '%s'\n" 164 " output: '%s'\n" 165 " rc: %Rrc\n" 166 " expected rc: %Rrc\n", 167 aRTPathAbsExTests[i].pcszInputBase, 168 aRTPathAbsExTests[i].pcszInputPath, 169 szPath, rc, 170 aRTPathAbsExTests[i].rc); 171 cErrors++; 172 continue; 173 } 174 175 char szTmp[RTPATH_MAX]; 176 char *pszExpected = NULL; 177 if (aRTPathAbsExTests[i].pcszOutput != NULL) 178 { 179 if (aRTPathAbsExTests[i].pcszOutput[0] == '%') 180 { 181 if (getcwd(szTmp, sizeof(szTmp)) == NULL) 182 { 183 RTPrintf("tstPath: getcwd failed with errno=%d!\n", errno); 184 cErrors++; 185 break; 186 } 187 188 pszExpected = szTmp; 189 190 if (aRTPathAbsExTests[i].pcszOutput[1] == 'p') 191 { 192 size_t cch = strlen(szTmp); 193 if (cch + strlen (aRTPathAbsExTests[i].pcszOutput) - 2 <= sizeof(szTmp)) 194 strcpy (szTmp + cch, aRTPathAbsExTests[i].pcszOutput + 2); 195 } 196 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 197 else if (aRTPathAbsExTests[i].pcszOutput[1] == 'd') 198 { 199 if (2 + strlen (aRTPathAbsExTests[i].pcszOutput) - 2 <= sizeof(szTmp)) 200 strcpy (szTmp + 2, aRTPathAbsExTests[i].pcszOutput + 2); 201 } 202 #endif 203 } 204 else 205 { 206 strcpy(szTmp, aRTPathAbsExTests[i].pcszOutput); 207 pszExpected = szTmp; 208 } 209 210 if (strcmp(szPath, pszExpected)) 211 { 212 RTPrintf("tstPath: RTPathAbsEx failed!\n" 213 " input base: '%s'\n" 214 " input path: '%s'\n" 215 " output: '%s'\n" 216 " expected: '%s'\n", 217 aRTPathAbsExTests[i].pcszInputBase, 218 aRTPathAbsExTests[i].pcszInputPath, 219 szPath, 220 aRTPathAbsExTests[i].pcszOutput); 221 cErrors++; 222 } 223 } 131 224 } 132 225
Note:
See TracChangeset
for help on using the changeset viewer.