VirtualBox

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

最後變更 在這個檔案從36675是 36675,由 vboxsync 提交於 14 年 前

nit

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 23.1 KB
 
1/* $Id: path-win.cpp 36675 2011-04-14 16:15:16Z 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.alldomusa.eu.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
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
184
185RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath)
186{
187 /*
188 * Validate input
189 */
190 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
191 AssertReturn(cchPath, VERR_INVALID_PARAMETER);
192
193 RTUTF16 wszPath[RTPATH_MAX];
194 HRESULT rc = SHGetFolderPathW(0, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, wszPath);
195 if ( rc == S_OK /* Found */
196 || rc == S_FALSE) /* Found, but doesn't exists */
197 /*
198 * Convert and return.
199 */
200 return RTUtf16ToUtf8Ex(&wszPath[0], RTSTR_MAX, &pszPath, cchPath, NULL);
201
202 return VERR_PATH_NOT_FOUND;
203}
204
205
206RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
207{
208 return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK);
209}
210
211
212RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
213{
214 /*
215 * Validate input.
216 */
217 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
218 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
219 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
220 AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
221 && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
222 ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
223 VERR_INVALID_PARAMETER);
224 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
225
226 /*
227 * Query file info.
228 */
229 WIN32_FILE_ATTRIBUTE_DATA Data;
230 PRTUTF16 pwszPath;
231 int rc = RTStrToUtf16(pszPath, &pwszPath);
232 if (RT_FAILURE(rc))
233 return rc;
234 if (!GetFileAttributesExW(pwszPath, GetFileExInfoStandard, &Data))
235 {
236 /* Fallback to FindFileFirst in case of sharing violation. */
237 if (GetLastError() == ERROR_SHARING_VIOLATION)
238 {
239 WIN32_FIND_DATAW FindData;
240 HANDLE hDir = FindFirstFileW(pwszPath, &FindData);
241 if (hDir == INVALID_HANDLE_VALUE)
242 {
243 rc = RTErrConvertFromWin32(GetLastError());
244 RTUtf16Free(pwszPath);
245 return rc;
246 }
247 FindClose(hDir);
248
249 Data.dwFileAttributes = FindData.dwFileAttributes;
250 Data.ftCreationTime = FindData.ftCreationTime;
251 Data.ftLastAccessTime = FindData.ftLastAccessTime;
252 Data.ftLastWriteTime = FindData.ftLastWriteTime;
253 Data.nFileSizeHigh = FindData.nFileSizeHigh;
254 Data.nFileSizeLow = FindData.nFileSizeLow;
255 }
256 else
257 {
258 rc = RTErrConvertFromWin32(GetLastError());
259 RTUtf16Free(pwszPath);
260 return rc;
261 }
262 }
263
264 /*
265 * Getting the information for the link target is a bit annoying and
266 * subject to the same access violation mess as above.. :/
267 */
268 /** @todo we're too lazy wrt to error paths here... */
269 if ( (fFlags & RTPATH_F_FOLLOW_LINK)
270 && (Data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
271 {
272 HANDLE hFinal = CreateFileW(pwszPath,
273 GENERIC_READ,
274 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
275 NULL,
276 OPEN_EXISTING,
277 FILE_FLAG_BACKUP_SEMANTICS,
278 NULL);
279 if (hFinal != INVALID_HANDLE_VALUE)
280 {
281 BY_HANDLE_FILE_INFORMATION FileData;
282 if (GetFileInformationByHandle(hFinal, &FileData))
283 {
284 Data.dwFileAttributes = FileData.dwFileAttributes;
285 Data.ftCreationTime = FileData.ftCreationTime;
286 Data.ftLastAccessTime = FileData.ftLastAccessTime;
287 Data.ftLastWriteTime = FileData.ftLastWriteTime;
288 Data.nFileSizeHigh = FileData.nFileSizeHigh;
289 Data.nFileSizeLow = FileData.nFileSizeLow;
290 }
291 CloseHandle(hFinal);
292 }
293 else if (GetLastError() != ERROR_SHARING_VIOLATION)
294 {
295 rc = RTErrConvertFromWin32(GetLastError());
296 RTUtf16Free(pwszPath);
297 return rc;
298 }
299 }
300
301 RTUtf16Free(pwszPath);
302
303 /*
304 * Setup the returned data.
305 */
306 pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32)
307 | (uint64_t)Data.nFileSizeLow;
308 pObjInfo->cbAllocated = pObjInfo->cbObject;
309
310 Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime));
311 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime);
312 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime);
313 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime);
314 pObjInfo->ChangeTime = pObjInfo->ModificationTime;
315
316 pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
317 pszPath, strlen(pszPath));
318
319 /*
320 * Requested attributes (we cannot provide anything actually).
321 */
322 switch (enmAdditionalAttribs)
323 {
324 case RTFSOBJATTRADD_NOTHING:
325 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
326 break;
327
328 case RTFSOBJATTRADD_UNIX:
329 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
330 pObjInfo->Attr.u.Unix.uid = ~0U;
331 pObjInfo->Attr.u.Unix.gid = ~0U;
332 pObjInfo->Attr.u.Unix.cHardlinks = 1;
333 pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /** @todo use volume serial number */
334 pObjInfo->Attr.u.Unix.INodeId = 0; /** @todo use fileid (see GetFileInformationByHandle). */
335 pObjInfo->Attr.u.Unix.fFlags = 0;
336 pObjInfo->Attr.u.Unix.GenerationId = 0;
337 pObjInfo->Attr.u.Unix.Device = 0;
338 break;
339
340 case RTFSOBJATTRADD_UNIX_OWNER:
341 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
342 pObjInfo->Attr.u.UnixOwner.uid = ~0U;
343 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
344 break;
345
346 case RTFSOBJATTRADD_UNIX_GROUP:
347 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
348 pObjInfo->Attr.u.UnixGroup.gid = ~0U;
349 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
350 break;
351
352 case RTFSOBJATTRADD_EASIZE:
353 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
354 pObjInfo->Attr.u.EASize.cb = 0;
355 break;
356
357 default:
358 AssertMsgFailed(("Impossible!\n"));
359 return VERR_INTERNAL_ERROR;
360 }
361
362 return VINF_SUCCESS;
363}
364
365
366RTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
367 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
368{
369 return RTPathSetTimesEx(pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, RTPATH_F_ON_LINK);
370}
371
372
373RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
374 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)
375{
376 /*
377 * Validate input.
378 */
379 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
380 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
381 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
382 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
383 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
384 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
385 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
386
387 /*
388 * Convert the path.
389 */
390 PRTUTF16 pwszPath;
391 int rc = RTStrToUtf16(pszPath, &pwszPath);
392 if (RT_SUCCESS(rc))
393 {
394 HANDLE hFile;
395 if (fFlags & RTPATH_F_FOLLOW_LINK)
396 hFile = CreateFileW(pwszPath,
397 FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */
398 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
399 NULL, /* security attribs */
400 OPEN_EXISTING, /* dwCreationDisposition */
401 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
402 NULL);
403 else
404 {
405/** @todo Symlink: Test RTPathSetTimesEx on Windows. (The code is disabled
406 * because it's not tested yet.) */
407#if 0 //def FILE_FLAG_OPEN_REPARSE_POINT
408 hFile = CreateFileW(pwszPath,
409 FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */
410 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
411 NULL, /* security attribs */
412 OPEN_EXISTING, /* dwCreationDisposition */
413 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT,
414 NULL);
415
416 if (hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER)
417#endif
418 hFile = CreateFileW(pwszPath,
419 FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */
420 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
421 NULL, /* security attribs */
422 OPEN_EXISTING, /* dwCreationDisposition */
423 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
424 NULL);
425 }
426 if (hFile != INVALID_HANDLE_VALUE)
427 {
428 /*
429 * Check if it's a no-op.
430 */
431 if (!pAccessTime && !pModificationTime && !pBirthTime)
432 rc = VINF_SUCCESS; /* NOP */
433 else
434 {
435 /*
436 * Convert the input and call the API.
437 */
438 FILETIME CreationTimeFT;
439 PFILETIME pCreationTimeFT = NULL;
440 if (pBirthTime)
441 pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT);
442
443 FILETIME LastAccessTimeFT;
444 PFILETIME pLastAccessTimeFT = NULL;
445 if (pAccessTime)
446 pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT);
447
448 FILETIME LastWriteTimeFT;
449 PFILETIME pLastWriteTimeFT = NULL;
450 if (pModificationTime)
451 pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT);
452
453 if (SetFileTime(hFile, pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT))
454 rc = VINF_SUCCESS;
455 else
456 {
457 DWORD Err = GetLastError();
458 rc = RTErrConvertFromWin32(Err);
459 Log(("RTPathSetTimes('%s', %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Rrc)\n",
460 pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc));
461 }
462 }
463 BOOL fRc = CloseHandle(hFile); Assert(fRc); NOREF(fRc);
464 }
465 else
466 {
467 DWORD Err = GetLastError();
468 rc = RTErrConvertFromWin32(Err);
469 Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and lasterr=%u\n", pszPath, rc, Err));
470 }
471
472 RTUtf16Free(pwszPath);
473 }
474
475 LogFlow(("RTPathSetTimes(%p:{%s}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}): return %Rrc\n",
476 pszPath, pszPath, pAccessTime, pAccessTime, pModificationTime, pModificationTime,
477 pChangeTime, pChangeTime, pBirthTime, pBirthTime));
478 return rc;
479}
480
481
482
483
484/**
485 * Internal worker for RTFileRename and RTFileMove.
486 *
487 * @returns iprt status code.
488 * @param pszSrc The source filename.
489 * @param pszDst The destination filename.
490 * @param fFlags The windows MoveFileEx flags.
491 * @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0,
492 * anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the
493 * source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
494 * not a directory (we are NOT checking whether it's a file).
495 */
496DECLHIDDEN(int) rtPathWin32MoveRename(const char *pszSrc, const char *pszDst, uint32_t fFlags, RTFMODE fFileType)
497{
498 /*
499 * Convert the strings.
500 */
501 PRTUTF16 pwszSrc;
502 int rc = RTStrToUtf16(pszSrc, &pwszSrc);
503 if (RT_SUCCESS(rc))
504 {
505 PRTUTF16 pwszDst;
506 rc = RTStrToUtf16(pszDst, &pwszDst);
507 if (RT_SUCCESS(rc))
508 {
509 /*
510 * Check object type if requested.
511 * This is open to race conditions.
512 */
513 if (fFileType)
514 {
515 DWORD dwAttr = GetFileAttributesW(pwszSrc);
516 if (dwAttr == INVALID_FILE_ATTRIBUTES)
517 rc = RTErrConvertFromWin32(GetLastError());
518 else if (RTFS_IS_DIRECTORY(fFileType))
519 rc = dwAttr & FILE_ATTRIBUTE_DIRECTORY ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
520 else
521 rc = dwAttr & FILE_ATTRIBUTE_DIRECTORY ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;
522 }
523 if (RT_SUCCESS(rc))
524 {
525 if (MoveFileExW(pwszSrc, pwszDst, fFlags))
526 rc = VINF_SUCCESS;
527 else
528 {
529 DWORD Err = GetLastError();
530 rc = RTErrConvertFromWin32(Err);
531 Log(("MoveFileExW('%s', '%s', %#x, %RTfmode): fails with rc=%Rrc & lasterr=%d\n",
532 pszSrc, pszDst, fFlags, fFileType, rc, Err));
533 }
534 }
535 RTUtf16Free(pwszDst);
536 }
537 RTUtf16Free(pwszSrc);
538 }
539 return rc;
540}
541
542
543RTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)
544{
545 /*
546 * Validate input.
547 */
548 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
549 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
550 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
551 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
552 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
553
554 /*
555 * Call the worker.
556 */
557 int rc = rtPathWin32MoveRename(pszSrc, pszDst, fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0, 0);
558
559 LogFlow(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
560 return rc;
561}
562
563
564RTDECL(bool) RTPathExists(const char *pszPath)
565{
566 return RTPathExistsEx(pszPath, RTPATH_F_FOLLOW_LINK);
567}
568
569
570RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags)
571{
572 /*
573 * Validate input.
574 */
575 AssertPtrReturn(pszPath, false);
576 AssertReturn(*pszPath, false);
577 Assert(RTPATH_F_IS_VALID(fFlags, 0));
578
579 /*
580 * Try query file info.
581 */
582 DWORD dwAttr;
583 PRTUTF16 pwszPath;
584 int rc = RTStrToUtf16(pszPath, &pwszPath);
585 if (RT_SUCCESS(rc))
586 {
587 dwAttr = GetFileAttributesW(pwszPath);
588 RTUtf16Free(pwszPath);
589 }
590 else
591 dwAttr = INVALID_FILE_ATTRIBUTES;
592 if (dwAttr == INVALID_FILE_ATTRIBUTES)
593 return false;
594
595#ifdef FILE_ATTRIBUTE_REPARSE_POINT
596 if ( (fFlags & RTPATH_F_FOLLOW_LINK)
597 && (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT))
598 {
599 AssertFailed();
600 /** @todo Symlinks: RTPathExists+RTPathExistsEx is misbehaving on symbolic
601 * links on Windows. */
602 }
603#endif
604
605 return true;
606}
607
608
609RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath)
610{
611 int rc;
612
613 /*
614 * GetCurrentDirectory may in some cases omit the drive letter, according
615 * to MSDN, thus the GetFullPathName call.
616 */
617 RTUTF16 wszCurPath[RTPATH_MAX];
618 if (GetCurrentDirectoryW(RTPATH_MAX, wszCurPath))
619 {
620 RTUTF16 wszFullPath[RTPATH_MAX];
621 if (GetFullPathNameW(wszCurPath, RTPATH_MAX, wszFullPath, NULL))
622 rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cchPath, NULL);
623 else
624 rc = RTErrConvertFromWin32(GetLastError());
625 }
626 else
627 rc = RTErrConvertFromWin32(GetLastError());
628 return rc;
629}
630
631
632RTDECL(int) RTPathSetCurrent(const char *pszPath)
633{
634 /*
635 * Validate input.
636 */
637 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
638 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
639
640 /*
641 * This interface is almost identical to the Windows API.
642 */
643 PRTUTF16 pwszPath;
644 int rc = RTStrToUtf16(pszPath, &pwszPath);
645 if (RT_SUCCESS(rc))
646 {
647 /** @todo improve the slash stripping a bit? */
648 size_t cwc = RTUtf16Len(pwszPath);
649 if ( cwc >= 2
650 && ( pwszPath[cwc - 1] == L'/'
651 || pwszPath[cwc - 1] == L'\\')
652 && pwszPath[cwc - 2] != ':')
653 pwszPath[cwc - 1] = L'\0';
654
655 if (!SetCurrentDirectoryW(pwszPath))
656 rc = RTErrConvertFromWin32(GetLastError());
657
658 RTUtf16Free(pwszPath);
659 }
660 return rc;
661}
662
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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