Skip to content

Commit e3edeb6

Browse files
committed
Merge branch 'development' of https://git01.codeplex.com/forks/gvessere/casablanca into 4gb_file_fix
2 parents 6f131b1 + 75534e3 commit e3edeb6

File tree

9 files changed

+455
-4
lines changed

9 files changed

+455
-4
lines changed

CONTRIBUTORS.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ Leslie Brody (Les1966)
1010
Michael M (M1xa)
1111
Matt Peterson (MattPeterson1)
1212

13-
13+
Illumina Inc.
14+
Gery Vessere ([email protected])

Release/src/streams/windows/fileio.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,11 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str
394394
else
395395
{
396396
pOverlapped->Offset = (DWORD)position;
397-
pOverlapped->OffsetHigh = 0x0;
397+
#ifdef _WIN64
398+
pOverlapped->OffsetHigh = (DWORD)(position >> 32);
399+
#else
400+
pOverlapped->OffsetHigh = 0;
401+
#endif
398402
}
399403

400404
_WriteRequest<streams::details::_file_info_impl>* req = nullptr;
@@ -491,7 +495,11 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre
491495
auto pOverlapped = new EXTENDED_OVERLAPPED(_ReadFileCompletionRoutine<streams::details::_file_info_impl>);
492496
pOverlapped->m_scheduler = scheduler.get();
493497
pOverlapped->Offset = (DWORD)offset;
498+
#ifdef _WIN64
499+
pOverlapped->OffsetHigh = (DWORD)(offset >> 32);
500+
#else
494501
pOverlapped->OffsetHigh = 0;
502+
#endif
495503

496504
_ReadRequest<streams::details::_file_info_impl>* req = nullptr;
497505

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/****************************** Module Header ******************************\
2+
* Module Name: CppSparseFile.cpp
3+
* Project: CppSparseFile
4+
* URL: http://code.msdn.microsoft.com/windowsapps/CppSparseFile-7f28156b
5+
* Copyright (c) Microsoft Corporation.
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
14+
* file size, and the query of sparse file layout.
15+
*
16+
* This source is subject to the Microsoft Public License.
17+
* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
18+
* All other rights reserved.
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
22+
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
23+
\***************************************************************************/
24+
25+
#pragma region Includes
26+
#include "stdafx.h"
27+
#include "CppSparseFile.h"
28+
#pragma endregion
29+
30+
31+
/*!
32+
* VolumeSupportsSparseFiles determines if the volume supports sparse streams.
33+
*
34+
* \param lpRootPathName
35+
* Volume root path e.g. C:\
36+
*/
37+
BOOL VolumeSupportsSparseFiles(LPCTSTR lpRootPathName)
38+
{
39+
DWORD dwVolFlags;
40+
GetVolumeInformation(lpRootPathName, NULL, MAX_PATH, NULL, NULL,
41+
&dwVolFlags, NULL, MAX_PATH);
42+
43+
return (dwVolFlags & FILE_SUPPORTS_SPARSE_FILES) ? TRUE : FALSE;
44+
}
45+
46+
47+
/*!
48+
* IsSparseFile determines if a file is sparse.
49+
*
50+
* \param lpFileName
51+
* File name
52+
*/
53+
BOOL IsSparseFile(LPCTSTR lpFileName)
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;
67+
}
68+
69+
70+
/*!
71+
* Get sparse file sizes.
72+
*
73+
* \param lpFileName
74+
* File name
75+
*
76+
* \see
77+
* http://msdn.microsoft.com/en-us/library/aa365276.aspx
78+
*/
79+
BOOL GetSparseFileSize(LPCTSTR lpFileName)
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"\nFile total size: %I64uKB\nActual size on disk: %I64uKB\n",
98+
liSparseFileSize.QuadPart / 1024,
99+
liSparseFileCompressedSize.QuadPart / 1024);
100+
101+
CloseHandle(hFile);
102+
return TRUE;
103+
}
104+
105+
106+
/*!
107+
* Create a sparse file.
108+
*
109+
* \param lpFileName
110+
* The name of the sparse file
111+
*/
112+
HANDLE CreateSparseFile(LPCTSTR lpFileName)
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;
130+
}
131+
132+
133+
/*!
134+
* Converting a file region to A sparse zero area.
135+
*
136+
* \param hSparseFile
137+
* Handle of the sparse file
138+
*
139+
* \param start
140+
* Start address of the sparse zero area
141+
*
142+
* \param size
143+
* Size of the sparse zero block. The minimum sparse size is 64KB.
144+
*
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
150+
* the FileStream.Seek function, otherwise DeviceIoControl will have no effect
151+
*/
152+
void SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size)
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);
164+
}
165+
166+
167+
/*!
168+
* Query the sparse file layout.
169+
*
170+
* \param lpFileName
171+
* File name
172+
*/
173+
BOOL GetSparseRanges(LPCTSTR lpFileName)
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"\nAllocated 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+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/***
2+
* ==++==
3+
*
4+
* Copyright (c) Microsoft Corporation. All rights reserved.
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* ==--==
17+
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
18+
*
19+
* CppSparseFile.h : defines various apis for creation and access of sparse files under windows
20+
*
21+
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
22+
****/
23+
24+
#pragma region Includes
25+
#include <stdio.h>
26+
#include <tchar.h>
27+
#include <windows.h>
28+
#include <assert.h>
29+
#pragma endregion
30+
31+
32+
/*!
33+
* VolumeSupportsSparseFiles determines if the volume supports sparse streams.
34+
*
35+
* \param lpRootPathName
36+
* Volume root path e.g. C:\
37+
*/
38+
BOOL VolumeSupportsSparseFiles(LPCTSTR lpRootPathName);
39+
40+
41+
/*!
42+
* IsSparseFile determines if a file is sparse.
43+
*
44+
* \param lpFileName
45+
* File name
46+
*/
47+
BOOL IsSparseFile(LPCTSTR lpFileName);
48+
49+
/*!
50+
* Get sparse file sizes.
51+
*
52+
* \param lpFileName
53+
* File name
54+
*
55+
* \see
56+
* http://msdn.microsoft.com/en-us/library/aa365276.aspx
57+
*/
58+
BOOL GetSparseFileSize(LPCTSTR lpFileName);
59+
60+
61+
/*!
62+
* Create a sparse file.
63+
*
64+
* \param lpFileName
65+
* The name of the sparse file
66+
*/
67+
HANDLE CreateSparseFile(LPCTSTR lpFileName);
68+
69+
/*!
70+
* Converting a file region to A sparse zero area.
71+
*
72+
* \param hSparseFile
73+
* Handle of the sparse file
74+
*
75+
* \param start
76+
* Start address of the sparse zero area
77+
*
78+
* \param size
79+
* Size of the sparse zero block. The minimum sparse size is 64KB.
80+
*
81+
* \remarks
82+
* Note that SetSparseRange does not perform actual file I/O, and unlike the
83+
* WriteFile function, it does not move the current file I/O pointer or sets
84+
* the end-of-file pointer. That is, if you want to place a sparse zero block
85+
* in the end of the file, you must move the file pointer accordingly using
86+
* the FileStream.Seek function, otherwise DeviceIoControl will have no effect
87+
*/
88+
void SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size);
89+
90+
/*!
91+
* Query the sparse file layout.
92+
*
93+
* \param lpFileName
94+
* File name
95+
*/
96+
BOOL GetSparseRanges(LPCTSTR lpFileName);

Release/tests/Functional/streams/VS11.xp/streams110_test.xp.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
</Link>
180180
</ItemDefinitionGroup>
181181
<ItemGroup>
182+
<ClCompile Include="..\CppSparseFile.cpp" />
182183
<ClCompile Include="..\memstream_tests.cpp" />
183184
<ClCompile Include="..\fuzz_tests.cpp" />
184185
<!-- Disabled to include following test files for Bug: 759503-->

Release/tests/Functional/streams/VS11/streams110_test.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
</Link>
180180
</ItemDefinitionGroup>
181181
<ItemGroup>
182+
<ClCompile Include="..\CppSparseFile.cpp" />
182183
<ClCompile Include="..\fstreambuf_tests.cpp" />
183184
<ClCompile Include="..\ostream_tests.cpp" />
184185
<ClCompile Include="..\stdstream_tests.cpp" />

0 commit comments

Comments
 (0)