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