VirtualBox

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

Last change on this file since 53825 was 53825, checked in by vboxsync, 10 years ago

Runtime: try the official Windows XP+ way to get the home (profile) directory, and if that doesn't work fall back to using the environment (without HOME as this isn't used on Windows)

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