VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win32/fs-win32.cpp@ 5285

Last change on this file since 5285 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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