VirtualBox

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

Last change on this file since 3991 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

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