VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/path-win.cpp@ 25240

Last change on this file since 25240 was 23375, checked in by vboxsync, 15 years ago

Very annoying assertion

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.1 KB
Line 
1/* $Id: path-win.cpp 23375 2009-09-28 13:14:29Z vboxsync $ */
2/** @file
3 * IPRT - Path manipulation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_PATH
36#include <Windows.h>
37
38#include <iprt/path.h>
39#include <iprt/assert.h>
40#include <iprt/string.h>
41#include <iprt/time.h>
42#include <iprt/mem.h>
43#include <iprt/param.h>
44#include <iprt/log.h>
45#include <iprt/err.h>
46#include "internal/path.h"
47#include "internal/fs.h"
48
49
50/**
51 * Get the real (no symlinks, no . or .. components) path, must exist.
52 *
53 * @returns iprt status code.
54 * @param pszPath The path to resolve.
55 * @param pszRealPath Where to store the real path.
56 * @param cchRealPath Size of the buffer.
57 */
58RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath)
59{
60 /*
61 * Convert to UTF-16, call Win32 APIs, convert back.
62 */
63 PRTUTF16 pwszPath;
64 int rc = RTStrToUtf16(pszPath, &pwszPath);
65 if (!RT_SUCCESS(rc))
66 return (rc);
67
68 LPWSTR lpFile;
69 WCHAR wsz[RTPATH_MAX];
70 rc = GetFullPathNameW((LPCWSTR)pwszPath, RT_ELEMENTS(wsz), &wsz[0], &lpFile);
71 if (rc > 0 && rc < RT_ELEMENTS(wsz))
72 {
73 /* Check that it exists. (Use RTPathAbs() to just resolve the name.) */
74 DWORD dwAttr = GetFileAttributesW(wsz);
75 if (dwAttr != INVALID_FILE_ATTRIBUTES)
76 rc = RTUtf16ToUtf8Ex((PRTUTF16)&wsz[0], RTSTR_MAX, &pszRealPath, cchRealPath, NULL);
77 else
78 rc = RTErrConvertFromWin32(GetLastError());
79 }
80 else if (rc <= 0)
81 rc = RTErrConvertFromWin32(GetLastError());
82 else
83 rc = VERR_FILENAME_TOO_LONG;
84
85 RTUtf16Free(pwszPath);
86
87 return rc;
88}
89
90
91/**
92 * Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
93 *
94 * @returns iprt status code.
95 * @param pszPath The path to resolve.
96 * @param pszAbsPath Where to store the absolute path.
97 * @param cchAbsPath Size of the buffer.
98 */
99RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
100{
101 /*
102 * Validation.
103 */
104 AssertPtr(pszAbsPath);
105 AssertPtr(pszPath);
106 if (RT_UNLIKELY(!*pszPath))
107 return VERR_INVALID_PARAMETER;
108
109 /*
110 * Convert to UTF-16, call Win32 API, convert back.
111 */
112 LPWSTR pwszPath;
113 int rc = RTStrToUtf16(pszPath, &pwszPath);
114 if (!RT_SUCCESS(rc))
115 return (rc);
116
117 LPWSTR pwszFile; /* Ignored */
118 RTUTF16 wsz[RTPATH_MAX];
119 rc = GetFullPathNameW(pwszPath, RT_ELEMENTS(wsz), &wsz[0], &pwszFile);
120 if (rc > 0 && rc < RT_ELEMENTS(wsz))
121 {
122 size_t cch;
123 rc = RTUtf16ToUtf8Ex(&wsz[0], RTSTR_MAX, &pszAbsPath, cchAbsPath, &cch);
124 if (RT_SUCCESS(rc))
125 {
126 /*
127 * Remove trailing slash if the path may be pointing to a directory.
128 * (See posix variant.)
129 */
130 if ( cch > 1
131 && RTPATH_IS_SLASH(pszAbsPath[cch - 1])
132 && !RTPATH_IS_VOLSEP(pszAbsPath[cch - 2])
133 && !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
134 pszAbsPath[cch - 1] = '\0';
135 }
136 }
137 else if (rc <= 0)
138 rc = RTErrConvertFromWin32(GetLastError());
139 else
140 rc = VERR_FILENAME_TOO_LONG;
141
142 RTUtf16Free(pwszPath);
143 return rc;
144}
145
146
147/**
148 * Gets the user home directory.
149 *
150 * @returns iprt status code.
151 * @param pszPath Buffer where to store the path.
152 * @param cchPath Buffer size in bytes.
153 */
154RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath)
155{
156 RTUTF16 wszPath[RTPATH_MAX];
157 DWORD dwAttr;
158
159 /*
160 * There are multiple definitions for what WE think of as user home...
161 */
162 if ( !GetEnvironmentVariableW(L"HOME", &wszPath[0], RTPATH_MAX)
163 || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES
164 || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
165 {
166 if ( !GetEnvironmentVariableW(L"USERPROFILE", &wszPath[0], RTPATH_MAX)
167 || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES
168 || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
169 {
170 /* %HOMEDRIVE%%HOMEPATH% */
171 if (!GetEnvironmentVariableW(L"HOMEDRIVE", &wszPath[0], RTPATH_MAX))
172 return VERR_PATH_NOT_FOUND;
173 size_t const cwc = RTUtf16Len(&wszPath[0]);
174 if ( !GetEnvironmentVariableW(L"HOMEPATH", &wszPath[cwc], RTPATH_MAX - (DWORD)cwc)
175 || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES
176 || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
177 return VERR_PATH_NOT_FOUND;
178 }
179 }
180
181 /*
182 * Convert and return.
183 */
184 return RTUtf16ToUtf8Ex(&wszPath[0], RTSTR_MAX, &pszPath, cchPath, NULL);
185}
186
187
188RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
189{
190 return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK);
191}
192
193
194RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
195{
196 /*
197 * Validate input.
198 */
199 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
200 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
201 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
202 AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
203 && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
204 ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
205 VERR_INVALID_PARAMETER);
206 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
207
208 /*
209 * Query file info.
210 */
211 WIN32_FILE_ATTRIBUTE_DATA Data;
212#ifndef RT_DONT_CONVERT_FILENAMES
213 PRTUTF16 pwszPath;
214 int rc = RTStrToUtf16(pszPath, &pwszPath);
215 if (RT_FAILURE(rc))
216 return rc;
217 if (!GetFileAttributesExW(pwszPath, GetFileExInfoStandard, &Data))
218 {
219 /* Fallback to FindFileFirst in case of sharing violation. */
220 if (GetLastError() == ERROR_SHARING_VIOLATION)
221 {
222 WIN32_FIND_DATAW FindData;
223 HANDLE hDir = FindFirstFileW(pwszPath, &FindData);
224 if (hDir == INVALID_HANDLE_VALUE)
225 {
226 rc = RTErrConvertFromWin32(GetLastError());
227 RTUtf16Free(pwszPath);
228 return rc;
229 }
230 FindClose(hDir);
231 Data.dwFileAttributes = FindData.dwFileAttributes;
232 Data.ftCreationTime = FindData.ftCreationTime;
233 Data.ftLastAccessTime = FindData.ftLastAccessTime;
234 Data.ftLastWriteTime = FindData.ftLastWriteTime;
235 Data.nFileSizeHigh = FindData.nFileSizeHigh;
236 Data.nFileSizeLow = FindData.nFileSizeLow;
237 }
238 else
239 {
240 rc = RTErrConvertFromWin32(GetLastError());
241 RTUtf16Free(pwszPath);
242 return rc;
243 }
244 }
245 RTUtf16Free(pwszPath);
246#else
247 if (!GetFileAttributesExA(pszPath, GetFileExInfoStandard, &Data))
248 {
249 /* Fallback to FindFileFirst in case of sharing violation. */
250 if (GetLastError() != ERROR_SHARING_VIOLATION)
251 return RTErrConvertFromWin32(GetLastError());
252 WIN32_FIND_DATAA FindData;
253 HANDLE hDir = FindFirstFileA(pszPath, &FindData);
254 if (hDir == INVALID_HANDLE_VALUE)
255 return RTErrConvertFromWin32(GetLastError());
256 FindClose(hDir);
257 Data.dwFileAttributes = FindData.dwFileAttributes;
258 Data.ftCreationTime = FindData.ftCreationTime;
259 Data.ftLastAccessTime = FindData.ftLastAccessTime;
260 Data.ftLastWriteTime = FindData.ftLastWriteTime;
261 Data.nFileSizeHigh = FindData.nFileSizeHigh;
262 Data.nFileSizeLow = FindData.nFileSizeLow;
263 }
264#endif
265 if ( (fFlags & RTPATH_F_FOLLOW_LINK)
266 && (Data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
267 {
268#ifndef DEBUG_sandervl
269 AssertFailed();
270#endif
271 /** @todo Symlinks: RTPathQueryInfoEx is not handling symbolic links
272 * correctly on Windows. (Both GetFileAttributesEx and FileFindFirst
273 * will return info about the symlink.) */
274 }
275
276 /*
277 * Setup the returned data.
278 */
279 pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32)
280 | (uint64_t)Data.nFileSizeLow;
281 pObjInfo->cbAllocated = pObjInfo->cbObject;
282
283 Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime));
284 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime);
285 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime);
286 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime);
287 pObjInfo->ChangeTime = pObjInfo->ModificationTime;
288
289 pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
290 pszPath, strlen(pszPath));
291
292 /*
293 * Requested attributes (we cannot provide anything actually).
294 */
295 switch (enmAdditionalAttribs)
296 {
297 case RTFSOBJATTRADD_EASIZE:
298 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
299 pObjInfo->Attr.u.EASize.cb = 0;
300 break;
301
302 case RTFSOBJATTRADD_UNIX:
303 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
304 pObjInfo->Attr.u.Unix.uid = ~0U;
305 pObjInfo->Attr.u.Unix.gid = ~0U;
306 pObjInfo->Attr.u.Unix.cHardlinks = 1;
307 pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /** @todo use volume serial number */
308 pObjInfo->Attr.u.Unix.INodeId = 0; /** @todo use fileid (see GetFileInformationByHandle). */
309 pObjInfo->Attr.u.Unix.fFlags = 0;
310 pObjInfo->Attr.u.Unix.GenerationId = 0;
311 pObjInfo->Attr.u.Unix.Device = 0;
312 break;
313
314 case RTFSOBJATTRADD_NOTHING:
315 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
316 break;
317
318 default:
319 AssertMsgFailed(("Impossible!\n"));
320 return VERR_INTERNAL_ERROR;
321 }
322
323 return VINF_SUCCESS;
324}
325
326
327RTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
328 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
329{
330 return RTPathSetTimesEx(pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, RTPATH_F_ON_LINK);
331}
332
333
334RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
335 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)
336{
337 /*
338 * Validate input.
339 */
340 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
341 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
342 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
343 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
344 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
345 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
346 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
347
348 /*
349 * Convert the path.
350 */
351 PRTUTF16 pwszPath;
352 int rc = RTStrToUtf16(pszPath, &pwszPath);
353 if (RT_SUCCESS(rc))
354 {
355 HANDLE hFile;
356 if (fFlags & RTPATH_F_FOLLOW_LINK)
357 hFile = CreateFileW(pwszPath,
358 FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */
359 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
360 NULL, /* security attribs */
361 OPEN_EXISTING, /* dwCreationDisposition */
362 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
363 NULL);
364 else
365 {
366/** @todo Symlink: Test RTPathSetTimesEx on Windows. (The code is disabled
367 * because it's not tested yet.) */
368#if 0 //def FILE_FLAG_OPEN_REPARSE_POINT
369 hFile = CreateFileW(pwszPath,
370 FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */
371 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
372 NULL, /* security attribs */
373 OPEN_EXISTING, /* dwCreationDisposition */
374 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT,
375 NULL);
376
377 if (hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER)
378#endif
379 hFile = CreateFileW(pwszPath,
380 FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */
381 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
382 NULL, /* security attribs */
383 OPEN_EXISTING, /* dwCreationDisposition */
384 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
385 NULL);
386 }
387 if (hFile != INVALID_HANDLE_VALUE)
388 {
389 /*
390 * Check if it's a no-op.
391 */
392 if (!pAccessTime && !pModificationTime && !pBirthTime)
393 rc = VINF_SUCCESS; /* NOP */
394 else
395 {
396 /*
397 * Convert the input and call the API.
398 */
399 FILETIME CreationTimeFT;
400 PFILETIME pCreationTimeFT = NULL;
401 if (pBirthTime)
402 pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT);
403
404 FILETIME LastAccessTimeFT;
405 PFILETIME pLastAccessTimeFT = NULL;
406 if (pAccessTime)
407 pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT);
408
409 FILETIME LastWriteTimeFT;
410 PFILETIME pLastWriteTimeFT = NULL;
411 if (pModificationTime)
412 pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT);
413
414 if (SetFileTime(hFile, pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT))
415 rc = VINF_SUCCESS;
416 else
417 {
418 DWORD Err = GetLastError();
419 rc = RTErrConvertFromWin32(Err);
420 Log(("RTPathSetTimes('%s', %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Rrc)\n",
421 pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc));
422 }
423 }
424 BOOL fRc = CloseHandle(hFile); Assert(fRc); NOREF(fRc);
425 }
426 else
427 {
428 DWORD Err = GetLastError();
429 rc = RTErrConvertFromWin32(Err);
430 Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and lasterr=%u\n", pszPath, rc, Err));
431 }
432
433 RTUtf16Free(pwszPath);
434 }
435
436 LogFlow(("RTPathSetTimes(%p:{%s}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}): return %Rrc\n",
437 pszPath, pszPath, pAccessTime, pAccessTime, pModificationTime, pModificationTime,
438 pChangeTime, pChangeTime, pBirthTime, pBirthTime));
439 return rc;
440}
441
442
443
444
445/**
446 * Internal worker for RTFileRename and RTFileMove.
447 *
448 * @returns iprt status code.
449 * @param pszSrc The source filename.
450 * @param pszDst The destination filename.
451 * @param fFlags The windows MoveFileEx flags.
452 * @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0,
453 * anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the
454 * source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
455 * not a directory (we are NOT checking whether it's a file).
456 */
457int rtPathWin32MoveRename(const char *pszSrc, const char *pszDst, uint32_t fFlags, RTFMODE fFileType)
458{
459 /*
460 * Convert the strings.
461 */
462 PRTUTF16 pwszSrc;
463 int rc = RTStrToUtf16(pszSrc, &pwszSrc);
464 if (RT_SUCCESS(rc))
465 {
466 PRTUTF16 pwszDst;
467 rc = RTStrToUtf16(pszDst, &pwszDst);
468 if (RT_SUCCESS(rc))
469 {
470 /*
471 * Check object type if requested.
472 * This is open to race conditions.
473 */
474 if (fFileType)
475 {
476 DWORD dwAttr = GetFileAttributesW(pwszSrc);
477 if (dwAttr == INVALID_FILE_ATTRIBUTES)
478 rc = RTErrConvertFromWin32(GetLastError());
479 else if (RTFS_IS_DIRECTORY(fFileType))
480 rc = dwAttr & FILE_ATTRIBUTE_DIRECTORY ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
481 else
482 rc = dwAttr & FILE_ATTRIBUTE_DIRECTORY ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;
483 }
484 if (RT_SUCCESS(rc))
485 {
486 if (MoveFileExW(pwszSrc, pwszDst, fFlags))
487 rc = VINF_SUCCESS;
488 else
489 {
490 DWORD Err = GetLastError();
491 rc = RTErrConvertFromWin32(Err);
492 Log(("MoveFileExW('%s', '%s', %#x, %RTfmode): fails with rc=%Rrc & lasterr=%d\n",
493 pszSrc, pszDst, fFlags, fFileType, rc, Err));
494 }
495 }
496 RTUtf16Free(pwszDst);
497 }
498 RTUtf16Free(pwszSrc);
499 }
500 return rc;
501}
502
503
504RTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)
505{
506 /*
507 * Validate input.
508 */
509 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
510 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
511 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
512 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
513 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
514
515 /*
516 * Call the worker.
517 */
518 int rc = rtPathWin32MoveRename(pszSrc, pszDst, fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0, 0);
519
520 LogFlow(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
521 return rc;
522}
523
524
525RTDECL(bool) RTPathExists(const char *pszPath)
526{
527 return RTPathExistsEx(pszPath, RTPATH_F_FOLLOW_LINK);
528}
529
530
531RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags)
532{
533 /*
534 * Validate input.
535 */
536 AssertPtrReturn(pszPath, false);
537 AssertReturn(*pszPath, false);
538 Assert(RTPATH_F_IS_VALID(fFlags, 0));
539
540 /*
541 * Try query file info.
542 */
543 DWORD dwAttr;
544#ifndef RT_DONT_CONVERT_FILENAMES
545 PRTUTF16 pwszPath;
546 int rc = RTStrToUtf16(pszPath, &pwszPath);
547 if (RT_SUCCESS(rc))
548 {
549 dwAttr = GetFileAttributesW(pwszPath);
550 RTUtf16Free(pwszPath);
551 }
552 else
553 dwAttr = INVALID_FILE_ATTRIBUTES;
554#else
555 dwAttr = GetFileAttributesA(pszPath);
556#endif
557
558 if (dwAttr == INVALID_FILE_ATTRIBUTES)
559 return false;
560
561#ifdef FILE_ATTRIBUTE_REPARSE_POINT
562 if ( (fFlags & RTPATH_F_FOLLOW_LINK)
563 && (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT))
564 {
565 AssertFailed();
566 /** @todo Symlinks: RTPathExists+RTPathExistsEx is misbehaving on symbolic
567 * links on Windows. */
568 }
569#endif
570
571 return true;
572}
573
574
575RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath)
576{
577 int rc;
578
579 /*
580 * GetCurrentDirectory may in some cases omit the drive letter, according
581 * to MSDN, thus the GetFullPathName call.
582 */
583#ifndef RT_DONT_CONVERT_FILENAMES
584 RTUTF16 wszCurPath[RTPATH_MAX];
585 if (GetCurrentDirectoryW(RTPATH_MAX, wszCurPath))
586 {
587 RTUTF16 wszFullPath[RTPATH_MAX];
588 if (GetFullPathNameW(wszCurPath, RTPATH_MAX, wszFullPath, NULL))
589 rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cchPath, NULL);
590 else
591 rc = RTErrConvertFromWin32(GetLastError());
592 }
593 else
594 rc = RTErrConvertFromWin32(GetLastError());
595#else
596 char szCurPath[RTPATH_MAX];
597 if (GetCurrentDirectory(RTPATH_MAX, szCurPath))
598 {
599 if (GetFullPathName(szCurPath, cchPath, pszPath, NULL))
600 rc = VINF_SUCCESS;
601 else
602 rc = RTErrConvertFromWin32(GetLastError());
603 }
604 else
605 rc = RTErrConvertFromWin32(GetLastError());
606#endif
607 return rc;
608}
609
610
611RTDECL(int) RTPathSetCurrent(const char *pszPath)
612{
613 /*
614 * Validate input.
615 */
616 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
617 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
618
619 /*
620 * This interface is almost identical to the Windows API.
621 */
622#ifndef RT_DONT_CONVERT_FILENAMES
623 PRTUTF16 pwszPath;
624 int rc = RTStrToUtf16(pszPath, &pwszPath);
625 if (RT_SUCCESS(rc))
626 {
627 /** @todo improove the slash stripping a bit? */
628 size_t cwc = RTUtf16Len(pwszPath);
629 if ( cwc >= 2
630 && ( pwszPath[cwc - 1] == L'/'
631 || pwszPath[cwc - 1] == L'\\')
632 && pwszPath[cwc - 2] != ':')
633 pwszPath[cwc - 1] = L'\0';
634
635 if (!SetCurrentDirectoryW(pwszPath))
636 rc = RTErrConvertFromWin32(GetLastError());
637
638 RTUtf16Free(pwszPath);
639 }
640#else
641 int rc = VINF_SUCCESS;
642 /** @todo improove the slash stripping a bit? */
643 char const *pszEnd = strchr(pszPath, '\0');
644 size_t const cchPath = pszPath - pszEnd;
645 if ( cchPath >= 2
646 && ( pszEnd[-1] == '/'
647 || pszEnd[-1] == '\\')
648 && pszEnd[-2] == ':')
649 {
650 char *pszCopy = (char *)RTMemTmpAlloc(cchPath);
651 if (pszCopy)
652 {
653 memcpy(pszCopy, pszPath, cchPath - 1);
654 pszCopy[cchPath - 1] = '\0';
655 if (!SetCurrentDirectory(pszCopy))
656 rc = RTErrConvertFromWin32(GetLastError());
657 RTMemTmpFree(pszCopy);
658 }
659 else
660 rc = VERR_NO_MEMORY;
661 }
662 else
663 {
664 if (!SetCurrentDirectory(pszPath))
665 rc = RTErrConvertFromWin32(GetLastError());
666 }
667#endif
668 return rc;
669}
670
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette