pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


queryallocatedrangestest1.c
Posted by Anonymous on Wed 26th Feb 2025 14:33
raw | new post

  1. /*
  2.  * MIT License
  3.  *
  4.  * Copyright (c) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7.  * of this software and associated documentation files (the "Software"), to deal
  8.  * in the Software without restriction, including without limitation the rights
  9.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10.  * copies of the Software, and to permit persons to whom the Software is
  11.  * furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included in all
  14.  * copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.  * SOFTWARE.
  23.  */
  24.  
  25. /*
  26.  * queryallocatedrangestest1.c - query sparse file data ranges
  27.  *
  28.  * Written by Roland Mainz <roland.mainz@nrubsig.org>
  29.  */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <stdbool.h>
  33. #include <windows.h>
  34. #include <winioctl.h>
  35.  
  36.  
  37.  
  38. static
  39. int fsctlqueryallocatedranges(const char *progname, const char *filename)
  40. {
  41.     HANDLE hFile;
  42.  
  43.     FILE_STANDARD_INFO finfo;
  44.     bool ok;
  45.  
  46.     DWORD bytesReturned = 0;
  47.     size_t max_ranges_per_query = 2;
  48.     PFILE_ALLOCATED_RANGE_BUFFER ranges = NULL;
  49.     FILE_ALLOCATED_RANGE_BUFFER inputBuffer;
  50.     /*
  51.      * |lastReturnedRange| - We start counting at |1| for
  52.      * compatibility with "fsutil sparse queryrange"
  53.      */
  54.     size_t lastReturnedRange = 1;
  55.     int retval = 0;
  56.     size_t i;
  57.     size_t cycle;
  58.     DWORD numRangesReturned;
  59.     DWORD lasterr;
  60.  
  61.     (void)memset(&finfo, 0, sizeof(finfo));
  62.  
  63.     ranges = malloc((sizeof(FILE_ALLOCATED_RANGE_BUFFER) * max_ranges_per_query));
  64.     if (ranges == NULL) {
  65.         (void)fprintf(stderr, "%s: Error out of memory\n", progname);
  66.         return 1;
  67.     }
  68.  
  69.     hFile = CreateFileA(filename,
  70.         GENERIC_READ,
  71.         FILE_SHARE_READ,
  72.         NULL,
  73.         OPEN_EXISTING,
  74.         FILE_ATTRIBUTE_NORMAL,
  75.         NULL);
  76.     if (hFile == INVALID_HANDLE_VALUE) {
  77.         (void)fprintf(stderr,
  78.             "%s: Error opening file '%s', lasterr=%d\n",
  79.             progname,
  80.             filename,
  81.             (int)GetLastError());
  82.         return 1;
  83.     }
  84.  
  85.     ok = GetFileInformationByHandleEx(hFile, FileStandardInfo, &finfo,
  86.         sizeof(finfo));
  87.     if (!ok) {
  88.         (void)fprintf(stderr, "%s: GetFileInformationByHandleEx() "
  89.             "error. GetLastError()==%d.\n",
  90.             progname,
  91.             (int)GetLastError());
  92.         retval = 1;
  93.         goto out;
  94.     }
  95.  
  96.     inputBuffer.FileOffset.QuadPart = 0ULL;
  97.     /*
  98.      * Set |inputBuffer.Length.QuadPart| to a value to query all
  99.      * data ranges in a file
  100.      *
  101.      * Notes:
  102.      * - |FILE_STANDARD_INFO.AllocationSize| can be zero on some
  103.      * filesystems, smaller than |FILE_STANDARD_INFO.EndOfFile|
  104.      * for sparse files and larger than
  105.      * |FILE_STANDARD_INFO.EndOfFile| for normal files, or value
  106.      * set by an user
  107.      * - Also add 1GB (0x40000000) to test the API
  108.      */
  109.     inputBuffer.Length.QuadPart =
  110.         max(finfo.AllocationSize.QuadPart,
  111.             finfo.EndOfFile.QuadPart) +
  112.         0x40000000;
  113.  
  114.     for (cycle = 0 ; ; cycle ++) {
  115. retry_fsctl:
  116.         if (!DeviceIoControl(hFile,
  117.             FSCTL_QUERY_ALLOCATED_RANGES,
  118.             &inputBuffer,  1*sizeof(FILE_ALLOCATED_RANGE_BUFFER),
  119.             ranges, (sizeof(FILE_ALLOCATED_RANGE_BUFFER) * max_ranges_per_query),
  120.             &bytesReturned,
  121.             NULL)) {
  122.             lasterr = GetLastError();
  123.             if (lasterr == ERROR_MORE_DATA) {
  124.                 /*
  125.                  * Windows BUG: NTFS on Win10 returns the number of
  126.                  * bytes we passed in, not the number of bytes which
  127.                  * we should allocate
  128.                  */
  129.                 max_ranges_per_query+=2;
  130.                 ranges = realloc(ranges,
  131.                     (sizeof(FILE_ALLOCATED_RANGE_BUFFER) * max_ranges_per_query));
  132.                 if (ranges == NULL) {
  133.                     (void)fprintf(stderr, "%s: Error out of memory\n",
  134.                         progname);
  135.                     retval = 1;
  136.                     goto out;
  137.                 }
  138.  
  139.                 /* |memset(..., 0, ...)| only here for debuging */
  140.                 (void)memset(ranges, 0, sizeof(FILE_ALLOCATED_RANGE_BUFFER) * max_ranges_per_query);
  141.                 goto retry_fsctl;
  142.             }
  143.  
  144.             retval = 1;
  145.             goto out;
  146.         }
  147.  
  148.         numRangesReturned = bytesReturned / sizeof(FILE_ALLOCATED_RANGE_BUFFER);
  149.  
  150.         if (numRangesReturned > 0) {
  151.             /*
  152.              * If we do more than one query make sure the data range
  153.              * offset we used to start the next query is the same
  154.              * as the first returned data range (both should be
  155.              * identical in offset)
  156.              */
  157.             if (cycle > 0) {
  158.                 if ((ranges[0].FileOffset.QuadPart != inputBuffer.FileOffset.QuadPart)) {
  159.                     (void)fprintf(stderr,
  160.                         "%s: Internal error: Restart query did not return "
  161.                         "the same data range offset\n",
  162.                         progname);
  163.                     retval = 1;
  164.                     goto out;
  165.                 }
  166.             }
  167.  
  168.             for (i = 0; i < numRangesReturned; i++) {
  169.                 if ((i < max_ranges_per_query) &&
  170.                     ((cycle > 0)?(i > 0):true)) {
  171.                     (void)printf("Data range[%ld]: Offset: 0x%llx, Length: 0x%llx\n",
  172.                         (unsigned long)lastReturnedRange++,
  173.                         (unsigned long long)ranges[i].FileOffset.QuadPart,
  174.                         (unsigned long long)ranges[i].Length.QuadPart);
  175.                 }
  176.             }
  177.  
  178.             inputBuffer.FileOffset.QuadPart = ranges[i-1].FileOffset.QuadPart;
  179.         }
  180.  
  181.         /* Done ? */
  182.         if (numRangesReturned < max_ranges_per_query)
  183.             break;
  184.     }
  185.  
  186. out:
  187.     (void)CloseHandle(hFile);
  188.     return retval;
  189. }
  190.  
  191. int main(int ac, char *av[])
  192. {
  193.     int retval;
  194.  
  195.     (void)ac; /* Unused */
  196.  
  197.     retval = fsctlqueryallocatedranges(av[0], av[1]);
  198.  
  199.     return retval;
  200. }

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.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at