VirtualBox

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

Last change on this file since 6749 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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