VirtualBox

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

Last change on this file since 36613 was 36613, checked in by vboxsync, 14 years ago

iprt: try to fix win burn

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

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