VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/fs-win.cpp@ 16684

Last change on this file since 16684 was 13837, checked in by vboxsync, 16 years ago

s/%Vr\([acfs]\)/%Rr\1/g - since I'm upsetting everyone anyway, better make the most of it...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.1 KB
Line 
1/* $Id: fs-win.cpp 13837 2008-11-05 02:54:02Z vboxsync $ */
2/** @file
3 * IPRT - File System, Win32.
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_FS
36#include <windows.h>
37
38#include <iprt/fs.h>
39#include <iprt/path.h>
40#include <iprt/string.h>
41#include <iprt/param.h>
42#include <iprt/err.h>
43#include <iprt/log.h>
44#include <iprt/assert.h>
45#include "internal/fs.h"
46
47
48/**
49 * Checks quickly if this is an correct root specification.
50 * Root specs ends with a slash of some kind.
51 *
52 * @returns indicator.
53 * @param pszFsPath Path to check.
54 */
55static bool rtFsIsRoot(const char *pszFsPath)
56{
57 /*
58 * UNC has exactly two slashes..
59 *
60 * Anything else starting with slashe(s) requires
61 * expansion and will have to take the long road.
62 */
63 if (RTPATH_IS_SLASH(pszFsPath[0]))
64 {
65 if ( !RTPATH_IS_SLASH(pszFsPath[1])
66 || RTPATH_IS_SLASH(pszFsPath[2]))
67 return false;
68
69 /* end of machine name */
70 const char *pszSlash = strpbrk(pszFsPath + 2, "\\/");
71 if (!pszSlash)
72 return false;
73
74 /* end of service name. */
75 pszSlash = strpbrk(pszSlash + 1, "\\/");
76 if (!pszSlash)
77 return false;
78
79 return pszSlash[1] == '\0';
80 }
81
82 /*
83 * Ok the other alternative is driver letter.
84 */
85 return pszFsPath[0] >= 'A' && pszFsPath[0] <= 'Z'
86 && pszFsPath[1] == ':'
87 && RTPATH_IS_SLASH(pszFsPath[2])
88 && !pszFsPath[3];
89}
90
91
92#ifndef RT_DONT_CONVERT_FILENAMES
93
94/**
95 * Finds the root of the specified volume.
96 *
97 * @returns iprt status code.
98 * @param pszFsPath Path within the filesystem. Verified as one byte or more.
99 * @param ppwszFsRoot Where to store the returned string. Free with rtFsFreeRoot(),
100 */
101static int rtFsGetRoot(const char *pszFsPath, PRTUTF16 *ppwszFsRoot)
102{
103 /*
104 * Do straight forward stuff first,
105 */
106 if (rtFsIsRoot(pszFsPath))
107 return RTStrToUtf16(pszFsPath, ppwszFsRoot);
108
109 /*
110 * Expand and add slash (if required).
111 */
112 char szFullPath[RTPATH_MAX];
113 int rc = RTPathAbs(pszFsPath, szFullPath, sizeof(szFullPath));
114 if (RT_FAILURE(rc))
115 return rc;
116 size_t cb = strlen(szFullPath);
117 if (!RTPATH_IS_SLASH(szFullPath[cb - 1]))
118 {
119 AssertReturn(cb + 1 < RTPATH_MAX, VERR_FILENAME_TOO_LONG);
120 szFullPath[cb] = '\\';
121 szFullPath[++cb] = '\0';
122 }
123
124 /*
125 * Convert the path.
126 */
127 rc = RTStrToUtf16(szFullPath, ppwszFsRoot);
128 if (RT_FAILURE(rc))
129 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
130
131 /*
132 * Walk the path until our proper API is happy or there is no more path left.
133 */
134 PRTUTF16 pwszStart = *ppwszFsRoot;
135 if (!GetVolumeInformationW(pwszStart, NULL, 0, NULL, NULL, 0, NULL, 0))
136 {
137 PRTUTF16 pwszEnd = pwszStart + RTUtf16Len(pwszStart);
138 PRTUTF16 pwszMin = pwszStart + 2;
139 do
140 {
141 /* Strip off the last path component. */
142 while (pwszEnd-- > pwszMin)
143 if (RTPATH_IS_SLASH(*pwszEnd))
144 break;
145 AssertReturn(pwszEnd >= pwszMin, VERR_INTERNAL_ERROR); /* leaks, but that's irrelevant for an internal error. */
146 pwszEnd[1] = '\0';
147 } while (!GetVolumeInformationW(pwszStart, NULL, 0, NULL, NULL, 0, NULL, 0));
148 }
149
150 return VINF_SUCCESS;
151}
152
153/**
154 * Frees string returned by rtFsGetRoot().
155 */
156static void rtFsFreeRoot(PRTUTF16 pwszFsRoot)
157{
158 RTUtf16Free(pwszFsRoot);
159}
160
161#else /* RT_DONT_CONVERT_FILENAMES */
162
163/**
164 * Finds the root of the specified volume.
165 *
166 * @returns iprt status code.
167 * @param pszFsPath Path within the filesystem. Verified as one byte or more.
168 * @param ppszFsRoot Where to store the returned string. Free with rtFsFreeRoot(),
169 */
170static int rtFsGetRoot(const char *pszFsPath, char **ppszFsRoot)
171{
172 /*
173 * Do straight forward stuff first,
174 */
175 if (rtFsIsRoot(pszFsPath))
176 return RTStrDupEx(ppszFsRoot, pszFsPath);
177
178 /*
179 * Expand and add slash (if required).
180 */
181 char szFullPath[RTPATH_MAX];
182 int rc = RTPathAbs(pszFsPath, szFullPath, sizeof(szFullPath));
183 if (RT_FAILURE(rc))
184 return rc;
185 size_t cb = strlen(szFullPath);
186 if (!RTPATH_IS_SLASH(szFullPath[cb - 1]))
187 {
188 AssertReturn(cb + 1 < RTPATH_MAX);
189 szFullPath[cb] = '\\';
190 szFullPath[++cb] = '\0';
191 }
192
193 /*
194 * Walk the path until our proper API is happy or there is no more path left.
195 */
196 if (GetVolumeInformation(szFullPath, NULL, 0, NULL, NULL, 0, NULL, 0))
197 {
198 char *pszEnd = szFullPath + cb;
199 char *pszMin = szFullPath + 2;
200 do
201 {
202 /* Strip off the last path component. */
203 while (pszEnd-- > pszMin)
204 if (RTPATH_IS_SLASH(*pszEnd))
205 break;
206 AssertReturn(pszEnd >= pszMin, VERR_INTERNAL_ERROR);
207 pszEnd[1] = '\0';
208 } while (GetVolumeInformationA(pszStart, NULL, 0, NULL, NULL, 0, NULL, 0));
209 }
210
211 return RTStrDupEx(ppszFsRoot, szFullPath);
212}
213
214/**
215 * Frees string returned by rtFsGetRoot().
216 */
217static void rtFsFreeRoot(char *pszFsRoot)
218{
219 RTStrFree(pszFsRoot);
220}
221
222#endif /* RT_DONT_CONVERT_FILENAMES*/
223
224
225RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pcbFree,
226 uint32_t *pcbBlock, uint32_t *pcbSector)
227{
228 /*
229 * Validate & get valid root path.
230 */
231 AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER);
232#ifndef RT_DONT_CONVERT_FILENAMES
233 PRTUTF16 pwszFsRoot;
234 int rc = rtFsGetRoot(pszFsPath, &pwszFsRoot);
235#else
236 char pszFsRoot;
237 int rc = rtFsGetRoot(pszFsPath, &pszFsRoot);
238#endif
239 if (RT_FAILURE(rc))
240 return rc;
241
242 /*
243 * Free and total.
244 */
245 if (pcbTotal || pcbFree)
246 {
247 ULARGE_INTEGER cbTotal;
248 ULARGE_INTEGER cbFree;
249#ifndef RT_DONT_CONVERT_FILENAMES
250 if (GetDiskFreeSpaceExW(pwszFsRoot, &cbFree, &cbTotal, NULL))
251#else
252 if (GetDiskFreeSpaceExA(pszFsRoot, &cbFree, &cbTotal, NULL))
253#endif
254 {
255 if (pcbTotal)
256 *pcbTotal = cbTotal.QuadPart;
257 if (pcbFree)
258 *pcbFree = cbFree.QuadPart;
259 }
260 else
261 {
262 DWORD Err = GetLastError();
263 rc = RTErrConvertFromWin32(Err);
264 Log(("RTFsQuerySizes(%s,): GetDiskFreeSpaceEx failed with lasterr %d (%Rrc)\n",
265 pszFsPath, Err, rc));
266 }
267 }
268
269 /*
270 * Block and sector size.
271 */
272 if ( RT_SUCCESS(rc)
273 && (pcbBlock || pcbSector))
274 {
275 DWORD dwDummy1, dwDummy2;
276 DWORD cbSector;
277 DWORD cSectorsPerCluster;
278#ifndef RT_DONT_CONVERT_FILENAMES
279 if (GetDiskFreeSpaceW(pwszFsRoot, &cSectorsPerCluster, &cbSector, &dwDummy1, &dwDummy2))
280#else
281 if (GetDiskFreeSpaceA(pszFsRoot, &cSectorsPerCluster, &cbSector, &dwDummy1, &dwDummy2))
282#endif
283 {
284 if (pcbBlock)
285 *pcbBlock = cbSector * cSectorsPerCluster;
286 if (pcbSector)
287 *pcbSector = cbSector;
288 }
289 else
290 {
291 DWORD Err = GetLastError();
292 rc = RTErrConvertFromWin32(Err);
293 Log(("RTFsQuerySizes(%s,): GetDiskFreeSpace failed with lasterr %d (%Rrc)\n",
294 pszFsPath, Err, rc));
295 }
296 }
297
298#ifndef RT_DONT_CONVERT_FILENAMES
299 rtFsFreeRoot(pwszFsRoot);
300#else
301 rtFsFreeRoot(pszFsRoot);
302#endif
303 return rc;
304}
305
306
307/**
308 * Query the serial number of a filesystem.
309 *
310 * @returns iprt status code.
311 * @param pszFsPath Path within the mounted filesystem.
312 * @param pu32Serial Where to store the serial number.
313 */
314RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
315{
316 /*
317 * Validate & get valid root path.
318 */
319 AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER);
320 AssertMsgReturn(VALID_PTR(pu32Serial), ("%p", pu32Serial), VERR_INVALID_PARAMETER);
321#ifndef RT_DONT_CONVERT_FILENAMES
322 PRTUTF16 pwszFsRoot;
323 int rc = rtFsGetRoot(pszFsPath, &pwszFsRoot);
324#else
325 char pszFsRoot;
326 int rc = rtFsGetRoot(pszFsPath, &pszFsRoot);
327#endif
328 if (RT_FAILURE(rc))
329 return rc;
330
331 /*
332 * Do work.
333 */
334 DWORD dwMaxName;
335 DWORD dwFlags;
336 DWORD dwSerial;
337#ifndef RT_DONT_CONVERT_FILENAMES
338 if (GetVolumeInformationW(pwszFsRoot, NULL, 0, &dwSerial, &dwMaxName, &dwFlags, NULL, 0))
339#else
340 if (GetVolumeInformationA(pszFsRoot, NULL, 0, &dwSerial, &dwMaxName, &dwFlags, NULL, 0))
341#endif
342 *pu32Serial = dwSerial;
343 else
344 {
345 DWORD Err = GetLastError();
346 rc = RTErrConvertFromWin32(Err);
347 Log(("RTFsQuerySizes(%s,): GetDiskFreeSpaceEx failed with lasterr %d (%Rrc)\n",
348 pszFsPath, Err, rc));
349 }
350
351#ifndef RT_DONT_CONVERT_FILENAMES
352 RTUtf16Free(pwszFsRoot);
353#else
354 RTStrFree(pszFsRoot);
355#endif
356 return rc;
357}
358
359
360/**
361 * Query the properties of a mounted filesystem.
362 *
363 * @returns iprt status code.
364 * @param pszFsPath Path within the mounted filesystem.
365 * @param pProperties Where to store the properties.
366 */
367RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties)
368{
369 /*
370 * Validate & get valid root path.
371 */
372 AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER);
373 AssertMsgReturn(VALID_PTR(pProperties), ("%p", pProperties), VERR_INVALID_PARAMETER);
374#ifndef RT_DONT_CONVERT_FILENAMES
375 PRTUTF16 pwszFsRoot;
376 int rc = rtFsGetRoot(pszFsPath, &pwszFsRoot);
377#else
378 char pszFsRoot;
379 int rc = rtFsGetRoot(pszFsPath, &pszFsRoot);
380#endif
381 if (RT_FAILURE(rc))
382 return rc;
383
384 /*
385 * Do work.
386 */
387 DWORD dwMaxName;
388 DWORD dwFlags;
389 DWORD dwSerial;
390#ifndef RT_DONT_CONVERT_FILENAMES
391 if (GetVolumeInformationW(pwszFsRoot, NULL, 0, &dwSerial, &dwMaxName, &dwFlags, NULL, 0))
392#else
393 if (GetVolumeInformationA(pszFsRoot, NULL, 0, &dwSerial, &dwMaxName, &dwFlags, NULL, 0))
394#endif
395 {
396 memset(pProperties, 0, sizeof(*pProperties));
397 pProperties->cbMaxComponent = dwMaxName;
398 pProperties->fFileCompression = !!(dwFlags & FILE_FILE_COMPRESSION);
399 pProperties->fCompressed = !!(dwFlags & FILE_VOLUME_IS_COMPRESSED);
400 pProperties->fReadOnly = !!(dwFlags & FILE_READ_ONLY_VOLUME);
401 pProperties->fSupportsUnicode = !!(dwFlags & FILE_UNICODE_ON_DISK);
402 pProperties->fCaseSensitive = false; /* win32 is case preserving only */
403 pProperties->fRemote = false; /* no idea yet */
404 }
405 else
406 {
407 DWORD Err = GetLastError();
408 rc = RTErrConvertFromWin32(Err);
409 Log(("RTFsQuerySizes(%s,): GetVolumeInformation failed with lasterr %d (%Rrc)\n",
410 pszFsPath, Err, rc));
411 }
412
413#ifndef RT_DONT_CONVERT_FILENAMES
414 RTUtf16Free(pwszFsRoot);
415#else
416 RTStrFree(pszFsRoot);
417#endif
418 return rc;
419}
420
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