4
4
* URL: http://code.msdn.microsoft.com/windowsapps/CppSparseFile-7f28156b
5
5
* Copyright (c) Microsoft Corporation.
6
6
*
7
- * CppSparseFile demonstrates the common operations on sparse files. A sparse
8
- * file is a type of computer file that attempts to use file system space more
9
- * efficiently when blocks allocated to the file are mostly empty. This is
10
- * achieved by writing brief information (metadata) representing the empty
11
- * blocks to disk instead of the actual "empty" space which makes up the
12
- * block, using less disk space. You can find in this example the creation of
13
- * sparse file, the detection of sparse attribute, the retrieval of sparse
7
+ * CppSparseFile demonstrates the common operations on sparse files. A sparse
8
+ * file is a type of computer file that attempts to use file system space more
9
+ * efficiently when blocks allocated to the file are mostly empty. This is
10
+ * achieved by writing brief information (metadata) representing the empty
11
+ * blocks to disk instead of the actual "empty" space which makes up the
12
+ * block, using less disk space. You can find in this example the creation of
13
+ * sparse file, the detection of sparse attribute, the retrieval of sparse
14
14
* file size, and the query of sparse file layout.
15
15
*
16
16
* This source is subject to the Microsoft Public License.
17
17
* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
18
18
* All other rights reserved.
19
19
*
20
- * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
21
- * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
20
+ * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
21
+ * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
22
22
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
23
23
\***************************************************************************/
24
24
36
36
*/
37
37
BOOL VolumeSupportsSparseFiles (LPCTSTR lpRootPathName)
38
38
{
39
- DWORD dwVolFlags;
40
- GetVolumeInformation (lpRootPathName, NULL , MAX_PATH, NULL , NULL ,
41
- &dwVolFlags, NULL , MAX_PATH);
39
+ DWORD dwVolFlags;
40
+ GetVolumeInformation (lpRootPathName, NULL , MAX_PATH, NULL , NULL ,
41
+ &dwVolFlags, NULL , MAX_PATH);
42
42
43
- return (dwVolFlags & FILE_SUPPORTS_SPARSE_FILES) ? TRUE : FALSE ;
43
+ return (dwVolFlags & FILE_SUPPORTS_SPARSE_FILES) ? TRUE : FALSE ;
44
44
}
45
45
46
46
@@ -52,18 +52,18 @@ BOOL VolumeSupportsSparseFiles(LPCTSTR lpRootPathName)
52
52
*/
53
53
BOOL IsSparseFile (LPCTSTR lpFileName)
54
54
{
55
- // Open the file for read
56
- HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, 0 , NULL ,
57
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
58
- if (hFile == INVALID_HANDLE_VALUE)
59
- return FALSE ;
60
-
61
- // Get file information
62
- BY_HANDLE_FILE_INFORMATION bhfi;
63
- GetFileInformationByHandle (hFile, &bhfi);
64
- CloseHandle (hFile);
65
-
66
- return (bhfi.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) ? TRUE : FALSE ;
55
+ // Open the file for read
56
+ HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, 0 , NULL ,
57
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
58
+ if (hFile == INVALID_HANDLE_VALUE)
59
+ return FALSE ;
60
+
61
+ // Get file information
62
+ BY_HANDLE_FILE_INFORMATION bhfi;
63
+ GetFileInformationByHandle (hFile, &bhfi);
64
+ CloseHandle (hFile);
65
+
66
+ return (bhfi.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) ? TRUE : FALSE ;
67
67
}
68
68
69
69
@@ -78,28 +78,28 @@ BOOL IsSparseFile(LPCTSTR lpFileName)
78
78
*/
79
79
BOOL GetSparseFileSize (LPCTSTR lpFileName)
80
80
{
81
- // Retrieves the size of the specified file, in bytes. The size includes
82
- // both allocated ranges and sparse ranges.
83
- HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, 0 , NULL ,
84
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
85
- if (hFile == INVALID_HANDLE_VALUE)
86
- return FALSE ;
87
- LARGE_INTEGER liSparseFileSize;
88
- GetFileSizeEx (hFile, &liSparseFileSize);
89
-
90
- // Retrieves the file's actual size on disk, in bytes. The size does not
91
- // include the sparse ranges.
92
- LARGE_INTEGER liSparseFileCompressedSize;
93
- liSparseFileCompressedSize.LowPart = GetCompressedFileSize (lpFileName,
94
- (LPDWORD)&liSparseFileCompressedSize.HighPart );
95
-
96
- // Print the result
97
- wprintf (L" \n File total size: %I64uKB\n Actual size on disk: %I64uKB\n " ,
98
- liSparseFileSize.QuadPart / 1024 ,
99
- liSparseFileCompressedSize.QuadPart / 1024 );
100
-
101
- CloseHandle (hFile);
102
- return TRUE ;
81
+ // Retrieves the size of the specified file, in bytes. The size includes
82
+ // both allocated ranges and sparse ranges.
83
+ HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, 0 , NULL ,
84
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
85
+ if (hFile == INVALID_HANDLE_VALUE)
86
+ return FALSE ;
87
+ LARGE_INTEGER liSparseFileSize;
88
+ GetFileSizeEx (hFile, &liSparseFileSize);
89
+
90
+ // Retrieves the file's actual size on disk, in bytes. The size does not
91
+ // include the sparse ranges.
92
+ LARGE_INTEGER liSparseFileCompressedSize;
93
+ liSparseFileCompressedSize.LowPart = GetCompressedFileSize (lpFileName,
94
+ (LPDWORD)&liSparseFileCompressedSize.HighPart );
95
+
96
+ // Print the result
97
+ wprintf (L" \n File total size: %I64uKB\n Actual size on disk: %I64uKB\n " ,
98
+ liSparseFileSize.QuadPart / 1024 ,
99
+ liSparseFileCompressedSize.QuadPart / 1024 );
100
+
101
+ CloseHandle (hFile);
102
+ return TRUE ;
103
103
}
104
104
105
105
@@ -111,22 +111,22 @@ BOOL GetSparseFileSize(LPCTSTR lpFileName)
111
111
*/
112
112
HANDLE CreateSparseFile (LPCTSTR lpFileName)
113
113
{
114
- // Create a normal file
115
- HANDLE hSparseFile = CreateFile (lpFileName, GENERIC_WRITE, 0 , NULL ,
116
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
117
-
118
- if (hSparseFile == INVALID_HANDLE_VALUE)
119
- return hSparseFile;
120
-
121
- // Use the DeviceIoControl function with the FSCTL_SET_SPARSE control
122
- // code to mark the file as sparse. If you don't mark the file as sparse,
123
- // the FSCTL_SET_ZERO_DATA control code will actually write zero bytes to
124
- // the file instead of marking the region as sparse zero area.
125
- DWORD dwTemp;
126
- DeviceIoControl (hSparseFile, FSCTL_SET_SPARSE, NULL , 0 , NULL , 0 , &dwTemp,
127
- NULL );
128
-
129
- return hSparseFile;
114
+ // Create a normal file
115
+ HANDLE hSparseFile = CreateFile (lpFileName, GENERIC_WRITE, 0 , NULL ,
116
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
117
+
118
+ if (hSparseFile == INVALID_HANDLE_VALUE)
119
+ return hSparseFile;
120
+
121
+ // Use the DeviceIoControl function with the FSCTL_SET_SPARSE control
122
+ // code to mark the file as sparse. If you don't mark the file as sparse,
123
+ // the FSCTL_SET_ZERO_DATA control code will actually write zero bytes to
124
+ // the file instead of marking the region as sparse zero area.
125
+ DWORD dwTemp;
126
+ DeviceIoControl (hSparseFile, FSCTL_SET_SPARSE, NULL , 0 , NULL , 0 , &dwTemp,
127
+ NULL );
128
+
129
+ return hSparseFile;
130
130
}
131
131
132
132
@@ -143,24 +143,24 @@ HANDLE CreateSparseFile(LPCTSTR lpFileName)
143
143
* Size of the sparse zero block. The minimum sparse size is 64KB.
144
144
*
145
145
* \remarks
146
- * Note that SetSparseRange does not perform actual file I/O, and unlike the
147
- * WriteFile function, it does not move the current file I/O pointer or sets
148
- * the end-of-file pointer. That is, if you want to place a sparse zero block
149
- * in the end of the file, you must move the file pointer accordingly using
146
+ * Note that SetSparseRange does not perform actual file I/O, and unlike the
147
+ * WriteFile function, it does not move the current file I/O pointer or sets
148
+ * the end-of-file pointer. That is, if you want to place a sparse zero block
149
+ * in the end of the file, you must move the file pointer accordingly using
150
150
* the FileStream.Seek function, otherwise DeviceIoControl will have no effect
151
151
*/
152
152
void SetSparseRange (HANDLE hSparseFile, LONGLONG start, LONGLONG size)
153
153
{
154
- // Specify the starting and the ending address (not the size) of the
155
- // sparse zero block
156
- FILE_ZERO_DATA_INFORMATION fzdi;
157
- fzdi.FileOffset .QuadPart = start;
158
- fzdi.BeyondFinalZero .QuadPart = start + size;
159
-
160
- // Mark the range as sparse zero block
161
- DWORD dwTemp;
162
- DeviceIoControl (hSparseFile, FSCTL_SET_ZERO_DATA, &fzdi, sizeof (fzdi),
163
- NULL , 0 , &dwTemp, NULL );
154
+ // Specify the starting and the ending address (not the size) of the
155
+ // sparse zero block
156
+ FILE_ZERO_DATA_INFORMATION fzdi;
157
+ fzdi.FileOffset .QuadPart = start;
158
+ fzdi.BeyondFinalZero .QuadPart = start + size;
159
+
160
+ // Mark the range as sparse zero block
161
+ DWORD dwTemp;
162
+ DeviceIoControl (hSparseFile, FSCTL_SET_ZERO_DATA, &fzdi, sizeof (fzdi),
163
+ NULL , 0 , &dwTemp, NULL );
164
164
}
165
165
166
166
@@ -172,70 +172,70 @@ void SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size)
172
172
*/
173
173
BOOL GetSparseRanges (LPCTSTR lpFileName)
174
174
{
175
- // Open the file for read
176
- HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, 0 , NULL ,
177
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
178
- if (hFile == INVALID_HANDLE_VALUE)
179
- return FALSE ;
180
-
181
- LARGE_INTEGER liFileSize;
182
- GetFileSizeEx (hFile, &liFileSize);
183
-
184
- // Range to be examined (the whole file)
185
- FILE_ALLOCATED_RANGE_BUFFER queryRange;
186
- queryRange.FileOffset .QuadPart = 0 ;
187
- queryRange.Length = liFileSize;
188
-
189
- // Allocated areas info
190
- FILE_ALLOCATED_RANGE_BUFFER allocRanges[1024 ];
191
-
192
- DWORD nbytes;
193
- BOOL fFinished ;
194
- _putws (L" \n Allocated ranges in the file:" );
195
- do
196
- {
197
- fFinished = DeviceIoControl (hFile, FSCTL_QUERY_ALLOCATED_RANGES,
198
- &queryRange, sizeof (queryRange), allocRanges,
199
- sizeof (allocRanges), &nbytes, NULL );
200
-
201
- if (!fFinished )
202
- {
203
- DWORD dwError = GetLastError ();
204
-
205
- // ERROR_MORE_DATA is the only error that is normal
206
- if (dwError != ERROR_MORE_DATA)
207
- {
208
- wprintf (L" DeviceIoControl failed w/err 0x%08lx\n " , dwError);
209
- CloseHandle (hFile);
210
- return FALSE ;
211
- }
212
- }
213
-
214
- // Calculate the number of records returned
215
- DWORD dwAllocRangeCount = nbytes /
216
- sizeof (FILE_ALLOCATED_RANGE_BUFFER);
217
-
218
- // Print each allocated range
219
- for (DWORD i = 0 ; i < dwAllocRangeCount; i++)
220
- {
221
- wprintf (L" allocated range: [%I64u] [%I64u]\n " ,
222
- allocRanges[i].FileOffset .QuadPart ,
223
- allocRanges[i].Length .QuadPart );
224
- }
225
-
226
- // Set starting address and size for the next query
227
- if (!fFinished && dwAllocRangeCount > 0 )
228
- {
229
- queryRange.FileOffset .QuadPart =
230
- allocRanges[dwAllocRangeCount - 1 ].FileOffset .QuadPart +
231
- allocRanges[dwAllocRangeCount - 1 ].Length .QuadPart ;
232
-
233
- queryRange.Length .QuadPart = liFileSize.QuadPart -
234
- queryRange.FileOffset .QuadPart ;
235
- }
236
-
237
- } while (!fFinished );
238
-
239
- CloseHandle (hFile);
240
- return TRUE ;
175
+ // Open the file for read
176
+ HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, 0 , NULL ,
177
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
178
+ if (hFile == INVALID_HANDLE_VALUE)
179
+ return FALSE ;
180
+
181
+ LARGE_INTEGER liFileSize;
182
+ GetFileSizeEx (hFile, &liFileSize);
183
+
184
+ // Range to be examined (the whole file)
185
+ FILE_ALLOCATED_RANGE_BUFFER queryRange;
186
+ queryRange.FileOffset .QuadPart = 0 ;
187
+ queryRange.Length = liFileSize;
188
+
189
+ // Allocated areas info
190
+ FILE_ALLOCATED_RANGE_BUFFER allocRanges[1024 ];
191
+
192
+ DWORD nbytes;
193
+ BOOL fFinished ;
194
+ _putws (L" \n Allocated ranges in the file:" );
195
+ do
196
+ {
197
+ fFinished = DeviceIoControl (hFile, FSCTL_QUERY_ALLOCATED_RANGES,
198
+ &queryRange, sizeof (queryRange), allocRanges,
199
+ sizeof (allocRanges), &nbytes, NULL );
200
+
201
+ if (!fFinished )
202
+ {
203
+ DWORD dwError = GetLastError ();
204
+
205
+ // ERROR_MORE_DATA is the only error that is normal
206
+ if (dwError != ERROR_MORE_DATA)
207
+ {
208
+ wprintf (L" DeviceIoControl failed w/err 0x%08lx\n " , dwError);
209
+ CloseHandle (hFile);
210
+ return FALSE ;
211
+ }
212
+ }
213
+
214
+ // Calculate the number of records returned
215
+ DWORD dwAllocRangeCount = nbytes /
216
+ sizeof (FILE_ALLOCATED_RANGE_BUFFER);
217
+
218
+ // Print each allocated range
219
+ for (DWORD i = 0 ; i < dwAllocRangeCount; i++)
220
+ {
221
+ wprintf (L" allocated range: [%I64u] [%I64u]\n " ,
222
+ allocRanges[i].FileOffset .QuadPart ,
223
+ allocRanges[i].Length .QuadPart );
224
+ }
225
+
226
+ // Set starting address and size for the next query
227
+ if (!fFinished && dwAllocRangeCount > 0 )
228
+ {
229
+ queryRange.FileOffset .QuadPart =
230
+ allocRanges[dwAllocRangeCount - 1 ].FileOffset .QuadPart +
231
+ allocRanges[dwAllocRangeCount - 1 ].Length .QuadPart ;
232
+
233
+ queryRange.Length .QuadPart = liFileSize.QuadPart -
234
+ queryRange.FileOffset .QuadPart ;
235
+ }
236
+
237
+ } while (!fFinished );
238
+
239
+ CloseHandle (hFile);
240
+ return TRUE ;
241
241
}
0 commit comments