- /*
- * MIT License
- *
- * Copyright (c) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- /*
- * queryallocatedrangestest1.c - query sparse file data ranges
- *
- * Written by Roland Mainz <roland.mainz@nrubsig.org>
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <windows.h>
- #include <winioctl.h>
- static
- int fsctlqueryallocatedranges(const char *progname, const char *filename)
- {
- HANDLE hFile;
- FILE_STANDARD_INFO finfo;
- bool ok;
- DWORD bytesReturned = 0;
- size_t max_ranges_per_query = 2;
- PFILE_ALLOCATED_RANGE_BUFFER ranges = NULL;
- FILE_ALLOCATED_RANGE_BUFFER inputBuffer;
- /*
- * |lastReturnedRange| - We start counting at |1| for
- * compatibility with "fsutil sparse queryrange"
- */
- size_t lastReturnedRange = 1;
- int retval = 0;
- size_t i;
- size_t cycle;
- DWORD numRangesReturned;
- DWORD lasterr;
- if (ranges == NULL) {
- return 1;
- }
- hFile = CreateFileA(filename,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (hFile == INVALID_HANDLE_VALUE) {
- "%s: Error opening file '%s', lasterr=%d\n",
- progname,
- filename,
- (int)GetLastError());
- return 1;
- }
- ok = GetFileInformationByHandleEx(hFile, FileStandardInfo, &finfo,
- sizeof(finfo));
- if (!ok) {
- "error. GetLastError()==%d.\n",
- progname,
- (int)GetLastError());
- retval = 1;
- goto out;
- }
- inputBuffer.FileOffset.QuadPart = 0ULL;
- /*
- * Set |inputBuffer.Length.QuadPart| to a value to query all
- * data ranges in a file
- *
- * Notes:
- * - |FILE_STANDARD_INFO.AllocationSize| can be zero on some
- * filesystems, smaller than |FILE_STANDARD_INFO.EndOfFile|
- * for sparse files and larger than
- * |FILE_STANDARD_INFO.EndOfFile| for normal files, or value
- * set by an user
- * - Also add 1GB (0x40000000) to test the API
- */
- inputBuffer.Length.QuadPart =
- max(finfo.AllocationSize.QuadPart,
- finfo.EndOfFile.QuadPart) +
- 0x40000000;
- for (cycle = 0 ; ; cycle ++) {
- retry_fsctl:
- if (!DeviceIoControl(hFile,
- FSCTL_QUERY_ALLOCATED_RANGES,
- &inputBuffer, 1*sizeof(FILE_ALLOCATED_RANGE_BUFFER),
- ranges, (sizeof(FILE_ALLOCATED_RANGE_BUFFER) * max_ranges_per_query),
- &bytesReturned,
- NULL)) {
- lasterr = GetLastError();
- if (lasterr == ERROR_MORE_DATA) {
- /*
- * Windows BUG: NTFS on Win10 returns the number of
- * bytes we passed in, not the number of bytes which
- * we should allocate
- */
- max_ranges_per_query+=2;
- (sizeof(FILE_ALLOCATED_RANGE_BUFFER) * max_ranges_per_query));
- if (ranges == NULL) {
- progname);
- retval = 1;
- goto out;
- }
- /* |memset(..., 0, ...)| only here for debuging */
- goto retry_fsctl;
- }
- retval = 1;
- goto out;
- }
- numRangesReturned = bytesReturned / sizeof(FILE_ALLOCATED_RANGE_BUFFER);
- if (numRangesReturned > 0) {
- /*
- * If we do more than one query make sure the data range
- * offset we used to start the next query is the same
- * as the first returned data range (both should be
- * identical in offset)
- */
- if (cycle > 0) {
- if ((ranges[0].FileOffset.QuadPart != inputBuffer.FileOffset.QuadPart)) {
- "%s: Internal error: Restart query did not return "
- "the same data range offset\n",
- progname);
- retval = 1;
- goto out;
- }
- }
- for (i = 0; i < numRangesReturned; i++) {
- if ((i < max_ranges_per_query) &&
- ((cycle > 0)?(i > 0):true)) {
- (unsigned long)lastReturnedRange++,
- (unsigned long long)ranges[i].FileOffset.QuadPart,
- (unsigned long long)ranges[i].Length.QuadPart);
- }
- }
- inputBuffer.FileOffset.QuadPart = ranges[i-1].FileOffset.QuadPart;
- }
- /* Done ? */
- if (numRangesReturned < max_ranges_per_query)
- break;
- }
- out:
- (void)CloseHandle(hFile);
- return retval;
- }
- int main(int ac, char *av[])
- {
- int retval;
- (void)ac; /* Unused */
- retval = fsctlqueryallocatedranges(av[0], av[1]);
- return retval;
- }
queryallocatedrangestest1.c
Posted by Anonymous on Wed 26th Feb 2025 14:33
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.