pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patches to implement |FSCTL_QUERY_ALLOCATED_RANGES| via NFSv4.2 SEEK, tests+misc, 2025-02-13
Posted by Anonymous on Thu 13th Feb 2025 16:01
raw | new post

  1. From 32253fd0cd66b75475ab687c2e3567ca53ada8f1 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Thu, 13 Feb 2025 13:21:26 +0100
  4. Subject: [PATCH 1/4] sys: Implement |FSCTL_SET_SPARSE|
  5.  
  6. Implement |FSCTL_SET_SPARSE|
  7.  
  8. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  9. ---
  10. sys/nfs41sys_fsctl.c | 65 ++++++++++++++++++++++++++++++++++++++++++++
  11.  1 file changed, 65 insertions(+)
  12.  
  13. diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
  14. index ee4c186..6cfa6b3 100644
  15. --- a/sys/nfs41sys_fsctl.c
  16. +++ b/sys/nfs41sys_fsctl.c
  17. @@ -315,6 +315,68 @@ out:
  18.      return status;
  19.  }
  20.  
  21. +static
  22. +NTSTATUS nfs41_SetSparse(
  23. +    IN OUT PRX_CONTEXT RxContext)
  24. +{
  25. +    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  26. +    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  27. +    __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
  28. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  29. +    __notnull PFILE_SET_SPARSE_BUFFER set_parse_buffer =
  30. +        (PFILE_SET_SPARSE_BUFFER)FsCtl->pInputBuffer;
  31. +
  32. +    DbgEn();
  33. +
  34. +    /*
  35. +     * Special case: No input buffer, so we treat this as if we got
  36. +     * |set_parse_buffer->SetSparse == TRUE|
  37. +     */
  38. +    if (FsCtl->InputBufferLength == 0) {
  39. +        /*
  40. +         * We treat all files on NFS as sparse files by default,
  41. +         * so setting the flag is just a (valid) NOP
  42. +         */
  43. +        DbgP("nfs41_SetSparse: "
  44. +            "SUCCESS: FsCtl->InputBufferLength==0, "
  45. +            "treating as SetSparse=TRUE for file '%wZ'\n",
  46. +            SrvOpen->pAlreadyPrefixedName);
  47. +        status = STATUS_SUCCESS;
  48. +        goto out;
  49. +    }
  50. +
  51. +    if (FsCtl->InputBufferLength < sizeof(FILE_SET_SPARSE_BUFFER)) {
  52. +        DbgP("nfs41_SetSparse: Buffer too small\n");
  53. +        status = STATUS_INVALID_PARAMETER;
  54. +        goto out;
  55. +    }
  56. +
  57. +    if (set_parse_buffer->SetSparse) {
  58. +        /*
  59. +         * We treat all files on NFS as sparse files by default,
  60. +         * so setting the flag is just a (valid) NOP
  61. +         */
  62. +        DbgP("nfs41_SetSparse: "
  63. +            "SUCCESS: SetSparse=TRUE for file '%wZ'\n",
  64. +            SrvOpen->pAlreadyPrefixedName);
  65. +        status = STATUS_SUCCESS;
  66. +    }
  67. +    else {
  68. +        /*
  69. +         * We cannot disable the sparse flag, as we treat all files
  70. +         * on NFS as sparse files
  71. +         */
  72. +        DbgP("nfs41_SetSparse: "
  73. +            "FAIL: Cannot set SetSparse=FALSE for file '%wZ'\n",
  74. +            SrvOpen->pAlreadyPrefixedName);
  75. +        status = STATUS_INVALID_PARAMETER;
  76. +    }
  77. +
  78. +out:
  79. +    DbgEx();
  80. +    return status;
  81. +}
  82. +
  83.  NTSTATUS nfs41_FsCtl(
  84.      IN OUT PRX_CONTEXT RxContext)
  85.  {
  86. @@ -336,6 +398,9 @@ NTSTATUS nfs41_FsCtl(
  87.      case FSCTL_QUERY_ALLOCATED_RANGES:
  88.          status = nfs41_QueryAllocatedRanges(RxContext);
  89.          break;
  90. +    case FSCTL_SET_SPARSE:
  91. +        status = nfs41_SetSparse(RxContext);
  92. +        break;
  93.      default:
  94.          break;
  95.      }
  96. --
  97. 2.45.1
  98.  
  99. From 09a5e6aca0162d7f4f2b1faf17769c9011a304db Mon Sep 17 00:00:00 2001
  100. From: Roland Mainz <roland.mainz@nrubsig.org>
  101. Date: Thu, 13 Feb 2025 13:23:00 +0100
  102. Subject: [PATCH 2/4] sys: Remove bogus |is_root_directory()| check from
  103.  |check_nfs41_queryallocatedranges_args()|
  104.  
  105. Remove bogus |is_root_directory()| check from |check_nfs41_queryallocatedranges_args()|
  106.  
  107. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  108. ---
  109. sys/nfs41sys_fsctl.c | 9 ---------
  110.  1 file changed, 9 deletions(-)
  111.  
  112. diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
  113. index 6cfa6b3..1799fe9 100644
  114. --- a/sys/nfs41sys_fsctl.c
  115. +++ b/sys/nfs41sys_fsctl.c
  116. @@ -77,15 +77,6 @@ NTSTATUS check_nfs41_queryallocatedranges_args(
  117.          &RxContext->LowIoContext.ParamsFor.FsCtl;
  118.      const USHORT HeaderLen = sizeof(FILE_ALLOCATED_RANGE_BUFFER);
  119.  
  120. -    /*
  121. -     * Must have a filename longer than vnetroot name,
  122. -     * or it's trying to operate on the volume itself
  123. -     */
  124. -    if (is_root_directory(RxContext)) {
  125. -        status = STATUS_INVALID_PARAMETER;
  126. -        goto out;
  127. -    }
  128. -
  129.      if (!FsCtl->pOutputBuffer) {
  130.          status = STATUS_INVALID_USER_BUFFER;
  131.          goto out;
  132. --
  133. 2.45.1
  134.  
  135. From 368db4039cd801fa745516adb8752b050b743ff5 Mon Sep 17 00:00:00 2001
  136. From: Roland Mainz <roland.mainz@nrubsig.org>
  137. Date: Thu, 13 Feb 2025 14:39:27 +0100
  138. Subject: [PATCH 3/4] daemon: Add more sparse file debug code
  139.  (|debug_list_sparsefile_datasections|)
  140.  
  141. Add more sparse file debug code (|debug_list_sparsefile_datasections|)
  142.  
  143. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  144. ---
  145. daemon/daemon_debug.c | 84 +++++++++++++++++++++++++++++++++++++++++++
  146.  daemon/daemon_debug.h |  2 ++
  147.  daemon/open.c         |  3 +-
  148.  3 files changed, 88 insertions(+), 1 deletion(-)
  149.  
  150. diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
  151. index 5ca7427..fa0f90c 100644
  152. --- a/daemon/daemon_debug.c
  153. +++ b/daemon/daemon_debug.c
  154. @@ -1304,6 +1304,90 @@ out:
  155.      dprintf_out("<-- debug_list_sparsefile_holes()\n");
  156.  }
  157.  
  158. +void debug_list_sparsefile_datasections(nfs41_open_state *state)
  159. +{
  160. +    uint64_t next_offset = 0ULL;
  161. +    uint64_t data_size = 0ULL;
  162. +    int data_seek_status;
  163. +    bool_t data_seek_sr_eof;
  164. +    uint64_t data_seek_sr_offset;
  165. +    int hole_seek_status;
  166. +    bool_t hole_seek_sr_eof;
  167. +    uint64_t hole_seek_sr_offset;
  168. +    int i;
  169. +
  170. +    stateid_arg stateid;
  171. +
  172. +    dprintf_out(
  173. +        "--> debug_list_sparsefile_datasections(state->path.path='%s')\n",
  174. +        state->path.path);
  175. +
  176. +    nfs41_open_stateid_arg(state, &stateid);
  177. +
  178. +    next_offset = 0;
  179. +
  180. +    /*
  181. +     * Limit to 100 cycles to avoid locking-up the client if
  182. +     * something unexpected happen
  183. +     */
  184. +    for (i=0 ; i < 100 ; i++) {
  185. +        data_seek_status = nfs42_seek(state->session,
  186. +            &state->file,
  187. +            &stateid,
  188. +            next_offset,
  189. +            NFS4_CONTENT_DATA,
  190. +            &data_seek_sr_eof,
  191. +            &data_seek_sr_offset);
  192. +        if (data_seek_status) {
  193. +            dprintf_out("SEEK_DATA failed "
  194. +            "OP_SEEK(sa_offset=%llu,sa_what=SEEK_DATA) "
  195. +            "failed with %d(='%s')\n",
  196. +            next_offset,
  197. +            data_seek_status,
  198. +            nfs_error_string(data_seek_status));
  199. +            goto out;
  200. +        }
  201. +
  202. +        next_offset = data_seek_sr_offset;
  203. +
  204. +        hole_seek_status = nfs42_seek(state->session,
  205. +            &state->file,
  206. +            &stateid,
  207. +            next_offset,
  208. +            NFS4_CONTENT_HOLE,
  209. +            &hole_seek_sr_eof,
  210. +            &hole_seek_sr_offset);
  211. +        if (hole_seek_status) {
  212. +            dprintf_out("SEEK_HOLE failed "
  213. +            "OP_SEEK(sa_offset=%llu,sa_what=SEEK_HOLE) "
  214. +            "failed with %d(='%s')\n",
  215. +            next_offset,
  216. +            hole_seek_status,
  217. +            nfs_error_string(hole_seek_status));
  218. +            goto out;
  219. +        }
  220. +
  221. +        next_offset = hole_seek_sr_offset;
  222. +
  223. +        data_size = hole_seek_sr_offset - data_seek_sr_offset;
  224. +
  225. +        dprintf_out("data_section: from "
  226. +            "%llu to %llu, size=%llu (data_eof=%d, hole_eof=%d)\n",
  227. +            data_seek_sr_offset,
  228. +            hole_seek_sr_offset,
  229. +            data_size,
  230. +            (int)data_seek_sr_eof,
  231. +            (int)hole_seek_sr_eof);
  232. +
  233. +        if (data_seek_sr_eof || hole_seek_sr_eof) {
  234. +            break;
  235. +        }
  236. +    }
  237. +
  238. +out:
  239. +    dprintf_out("<-- debug_list_sparsefile_datasections()\n");
  240. +}
  241. +
  242.  #define NUM_RECENTLY_DELETED 128
  243.  static struct
  244.  {
  245. diff --git a/daemon/daemon_debug.h b/daemon/daemon_debug.h
  246. index b39a312..fd0f7b7 100644
  247. --- a/daemon/daemon_debug.h
  248. +++ b/daemon/daemon_debug.h
  249. @@ -155,6 +155,8 @@ const char* secflavorop2name(DWORD sec_flavor);
  250.  void print_nfs41_file_info(const char *label, const void *vinfo);
  251.  typedef struct __nfs41_open_state nfs41_open_state;
  252.  void debug_list_sparsefile_holes(nfs41_open_state *state);
  253. +void debug_list_sparsefile_datasections(nfs41_open_state *state);
  254. +
  255.  
  256.  /* pnfs_debug.c */
  257.  enum pnfs_status;
  258. diff --git a/daemon/open.c b/daemon/open.c
  259. index 681c8bf..2fbea48 100644
  260. --- a/daemon/open.c
  261. +++ b/daemon/open.c
  262. @@ -1182,7 +1182,8 @@ create_chgrp_out:
  263.      if ((status == 0) &&
  264.          (info.type == NF4REG) &&
  265.          (state->session->client->root->nfsminorvers >= 2)) {
  266. -        debug_list_sparsefile_holes(state);
  267. +        //debug_list_sparsefile_holes(state);
  268. +        debug_list_sparsefile_datasections(state);
  269.      }
  270.  #endif /* DEBUG_OPEN_SPARSE_FILES */
  271.  
  272. --
  273. 2.45.1
  274.  
  275. From 25453b8572671e98bd0567a56bf4eb7760f8abc2 Mon Sep 17 00:00:00 2001
  276. From: Roland Mainz <roland.mainz@nrubsig.org>
  277. Date: Thu, 13 Feb 2025 16:50:26 +0100
  278. Subject: [PATCH 4/4] cygwin,daemon,tests: Implement
  279.  |FSCTL_QUERY_ALLOCATED_RANGES| via NFSv4.2 SEEK
  280.  
  281. Implement |FSCTL_QUERY_ALLOCATED_RANGES| via NFSv4.2 SEEK, plus
  282. add simple test script.
  283.  
  284. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  285. ---
  286. cygwin/Makefile.install               |   2 +
  287.  daemon/fsctl.c                        | 162 +++++++++++++++++++++-----
  288.  tests/manual_testing.txt              |   5 +
  289.  tests/sparsefiles/testsparsefile1.ksh | 118 +++++++++++++++++++
  290.  4 files changed, 261 insertions(+), 26 deletions(-)
  291.  create mode 100644 tests/sparsefiles/testsparsefile1.ksh
  292.  
  293. diff --git a/cygwin/Makefile.install b/cygwin/Makefile.install
  294. index 8a4b878..98e4235 100644
  295. --- a/cygwin/Makefile.install
  296. +++ b/cygwin/Makefile.install
  297. @@ -36,6 +36,7 @@ installdest:
  298.         mkdir -p $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client
  299.         mkdir -p $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests
  300.         mkdir -p $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/misc
  301. +       mkdir -p $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/sparsefiles
  302.         cp $(VS_BUILD_DIR)/nfsd.exe             $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/nfsd_debug.exe
  303.         cp $(VS_BUILD_DIR)/nfsd.pdb             $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/nfsd_debug.pdb
  304.         cp $(VS_BUILD_DIR)/nfs_mount.*  $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/.
  305. @@ -110,6 +111,7 @@ installdest:
  306.                 cp "$(PROJECT_BASEDIR_DIR)/tests/ea/nfs_ea.i686.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/nfs_ea.exe ; \
  307.         fi
  308.         cp $(PROJECT_BASEDIR_DIR)/tests/nfsbuildtest/nfsbuildtest.ksh93 $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/misc/nfsbuildtest.ksh93
  309. +       cp $(PROJECT_BASEDIR_DIR)/tests/sparsefiles/testsparsefile1.ksh $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/sparsefiles/testsparsefile1.ksh
  310.         cp $(PROJECT_BASEDIR_DIR)/tests/fstest_make_numtree1/fstest_make_numtree1.ksh93 $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/misc/fstest_make_numtree1.ksh93
  311.         cp $(PROJECT_BASEDIR_DIR)/tests/wintartests/wintartest_comparewinvsgnu001.bash $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/misc/wintartest_comparewinvsgnu001.bash
  312.         cp $(PROJECT_BASEDIR_DIR)/tests/wintartests/wintartest_seq001.bash $(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/msnfs41client/tests/misc/wintartest_seq001.bash
  313. diff --git a/daemon/fsctl.c b/daemon/fsctl.c
  314. index 2eb85ee..61b9dca 100644
  315. --- a/daemon/fsctl.c
  316. +++ b/daemon/fsctl.c
  317. @@ -27,6 +27,8 @@
  318.  #include "daemon_debug.h"
  319.  #include "util.h"
  320.  
  321. +#define QARLVL 2 /* dprintf level for "query allocated ranges" logging */
  322. +
  323.  static int parse_queryallocatedranges(unsigned char *buffer,
  324.      uint32_t length, nfs41_upcall *upcall)
  325.  {
  326. @@ -40,7 +42,7 @@ static int parse_queryallocatedranges(unsigned char *buffer,
  327.      status = safe_read(&buffer, &length, &args->outbuffer, sizeof(args->outbuffer));
  328.      if (status) goto out;
  329.  
  330. -    DPRINTF(0, ("parse_queryallocatedranges: "
  331. +    DPRINTF(QARLVL, ("parse_queryallocatedranges: "
  332.          "parsing '%s' inrange=(FileOffset=%lld Length=%lld) "
  333.          "outbuffersize=%lu outbuffer=0x%p\n",
  334.          opcode2string(upcall->opcode),
  335. @@ -52,8 +54,113 @@ out:
  336.      return status;
  337.  }
  338.  
  339. +static
  340. +int query_sparsefile_datasections(nfs41_open_state *state,
  341. +    uint64_t start_offset,
  342. +    FILE_ALLOCATED_RANGE_BUFFER *outbuffer,
  343. +    size_t out_maxrecords,
  344. +    size_t *restrict res_num_records)
  345. +{
  346. +    int status = NO_ERROR;
  347. +    uint64_t next_offset;
  348. +    uint64_t data_size;
  349. +    int data_seek_status;
  350. +    bool_t data_seek_sr_eof;
  351. +    uint64_t data_seek_sr_offset;
  352. +    int hole_seek_status;
  353. +    bool_t hole_seek_sr_eof;
  354. +    uint64_t hole_seek_sr_offset;
  355. +    size_t i;
  356. +
  357. +    stateid_arg stateid;
  358. +
  359. +    DPRINTF(QARLVL,
  360. +        ("--> query_sparsefile_datasections(state->path.path='%s')\n",
  361. +        state->path.path));
  362. +
  363. +    /* NFS SEEK requires NFSv4.2 */
  364. +    if (state->session->client->root->nfsminorvers < 2) {
  365. +        status = ERROR_NOT_SUPPORTED;
  366. +        goto out;
  367. +    }
  368.  
  369. -static int handle_queryallocatedranges(void *daemon_context, nfs41_upcall *upcall)
  370. +    nfs41_open_stateid_arg(state, &stateid);
  371. +
  372. +    next_offset = start_offset;
  373. +    *res_num_records = 0;
  374. +
  375. +    for (i=0 ; i < out_maxrecords ; i++) {
  376. +        data_seek_status = nfs42_seek(state->session,
  377. +            &state->file,
  378. +            &stateid,
  379. +            next_offset,
  380. +            NFS4_CONTENT_DATA,
  381. +            &data_seek_sr_eof,
  382. +            &data_seek_sr_offset);
  383. +        if (data_seek_status) {
  384. +            status = nfs_to_windows_error(data_seek_status,
  385. +                ERROR_INVALID_PARAMETER);
  386. +            DPRINTF(QARLVL, ("SEEK_DATA failed "
  387. +                "OP_SEEK(sa_offset=%llu,sa_what=SEEK_DATA) "
  388. +                "failed with %d(='%s')\n",
  389. +                next_offset,
  390. +                data_seek_status,
  391. +                nfs_error_string(data_seek_status)));
  392. +            goto out;
  393. +        }
  394. +
  395. +        next_offset = data_seek_sr_offset;
  396. +
  397. +        hole_seek_status = nfs42_seek(state->session,
  398. +            &state->file,
  399. +            &stateid,
  400. +            next_offset,
  401. +            NFS4_CONTENT_HOLE,
  402. +            &hole_seek_sr_eof,
  403. +            &hole_seek_sr_offset);
  404. +        if (hole_seek_status) {
  405. +            status = nfs_to_windows_error(hole_seek_status,
  406. +                ERROR_INVALID_PARAMETER);
  407. +            DPRINTF(QARLVL, ("SEEK_HOLE failed "
  408. +                "OP_SEEK(sa_offset=%llu,sa_what=SEEK_HOLE) "
  409. +                "failed with %d(='%s')\n",
  410. +                next_offset,
  411. +                hole_seek_status,
  412. +                nfs_error_string(hole_seek_status)));
  413. +            goto out;
  414. +        }
  415. +
  416. +        next_offset = hole_seek_sr_offset;
  417. +
  418. +        data_size = hole_seek_sr_offset - data_seek_sr_offset;
  419. +
  420. +        DPRINTF(QARLVL, ("data_section: from "
  421. +            "%llu to %llu, size=%llu (data_eof=%d, hole_eof=%d)\n",
  422. +            data_seek_sr_offset,
  423. +            hole_seek_sr_offset,
  424. +            data_size,
  425. +            (int)data_seek_sr_eof,
  426. +            (int)hole_seek_sr_eof));
  427. +
  428. +        outbuffer[i].FileOffset.QuadPart = data_seek_sr_offset;
  429. +        outbuffer[i].Length.QuadPart = data_size;
  430. +        (*res_num_records)++;
  431. +
  432. +        if (data_seek_sr_eof || hole_seek_sr_eof) {
  433. +            break;
  434. +        }
  435. +    }
  436. +
  437. +out:
  438. +    DPRINTF(QARLVL, ("<-- query_sparsefile_datasections(), status=0x%x\n",
  439. +        status));
  440. +    return status;
  441. +}
  442. +
  443. +
  444. +static
  445. +int handle_queryallocatedranges(void *daemon_context,
  446. +    nfs41_upcall *upcall)
  447.  {
  448.      queryallocatedranges_upcall_args *args =
  449.          &upcall->args.queryallocatedranges;
  450. @@ -61,41 +168,44 @@ static int handle_queryallocatedranges(void *daemon_context, nfs41_upcall *upcal
  451.      PFILE_ALLOCATED_RANGE_BUFFER outbuffer =
  452.          (PFILE_ALLOCATED_RANGE_BUFFER)args->outbuffer;
  453.      int status = ERROR_INVALID_PARAMETER;
  454. -    nfs41_file_info info;
  455. +    size_t num_records;
  456.  
  457. -    DPRINTF(0,
  458. +    DPRINTF(QARLVL,
  459.          ("--> handle_queryallocatedranges("
  460. -            "state->path.path='%s')\n",
  461. -            state->path.path));
  462. -
  463. -    DPRINTF(0,
  464. +            "state->path.path='%s', "
  465. +            "args->inrange.FileOffset=%llu, "
  466. +            "args->inrange.Length=%llu)\n",
  467. +            state->path.path,
  468. +            args->inrange.FileOffset.QuadPart,
  469. +            args->inrange.Length.QuadPart));
  470. +
  471. +    num_records =
  472. +        ((size_t)args->outbuffersize /
  473. +            sizeof(FILE_ALLOCATED_RANGE_BUFFER));
  474. +
  475. +    DPRINTF(QARLVL,
  476.          ("handle_queryallocatedranges:"
  477.              "got space for %ld records\n",
  478. -            (int)((size_t)args->outbuffersize / sizeof(FILE_ALLOCATED_RANGE_BUFFER))));
  479. +            (int)num_records));
  480.  
  481.      args->returned_size = 0;
  482.  
  483. -    (void)memset(&info, 0, sizeof(info));
  484. +    size_t res_num_records = 0;
  485.  
  486. -    status = nfs41_cached_getattr(state->session,
  487. -        &state->file, &info);
  488. -    if (status)
  489. -        goto out;
  490. +    status = query_sparsefile_datasections(state,
  491. +        args->inrange.FileOffset.QuadPart,
  492. +        outbuffer,
  493. +        num_records,
  494. +        &res_num_records);
  495.  
  496. -    if (args->outbuffersize < (1*sizeof(FILE_ALLOCATED_RANGE_BUFFER))) {
  497. -        /* FIXME: We should return the size of the required buffer */
  498. -        status = ERROR_INSUFFICIENT_BUFFER;
  499. -        goto out;
  500. +    if (!status) {
  501. +        args->returned_size =
  502. +            (ULONG)res_num_records*sizeof(FILE_ALLOCATED_RANGE_BUFFER);
  503.      }
  504.  
  505. -    /* return size of file */
  506. -    outbuffer[0].FileOffset.QuadPart = 0;
  507. -    outbuffer[0].Length.QuadPart = info.size;
  508. -    args->returned_size = 1*sizeof(FILE_ALLOCATED_RANGE_BUFFER);
  509. -    status = NO_ERROR;
  510. -
  511. -out:
  512. -    DPRINTF(0, ("<-- handle_queryallocatedranges(), status=0x%lx\n", status));
  513. +    DPRINTF(QARLVL,
  514. +        ("<-- handle_queryallocatedranges(), status=0x%lx\n",
  515. +        status));
  516.      return status;
  517.  }
  518.  
  519. diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
  520. index 75f2053..13b82f6 100644
  521. --- a/tests/manual_testing.txt
  522. +++ b/tests/manual_testing.txt
  523. @@ -582,5 +582,10 @@ $ apt-get upgrade
  524.  # install packages for testing
  525.  $ apt-get install clang gcc gdb nedit emacs vim x11-apps xterm ksh traceroute strace ddd mesa-utils tk xpdf xmpuzzles mwm xutils-dev valgrind crash libhugetlbfs-bin wireguard xtron x11-xserver-utils sunclock moreutils iproute2 inetutils-tools build-essential linux-source libncurses5-dev xvkbd ethtool tshark xmldiff krb5-user krb5-kdc libkrb5-dev keyutils info bc kmod cpio flex libncurses5-dev libelf-dev libssl-dev inkscape xdmx xdmx-tools twm mwm sbuild autoconf automake openbsd-inetd rwho rwhod finger fingerd cronutils at nfs-kernel-server nfs-common nfs4-acl-tools autofs openjdk-17-jdk openjdk-17-demo python talk talkd libcurl4 libc6-dbg sysvbanner powertop iftop acpidump linux-perf ltrace locales task-german task-japanese schroot groff squashfs-tools dpkg-dev devscripts kernel-wedge sbsigntool git-svn apt-file module-assistant dwarves tree net-tools bridge-utils xnest uml-utilities inxi libxaw7-dev whois extrace kexec-tools dos2unix pkg-config libglib2.0-dev libpixman-1-dev qemu qemu-utils qemu-system-\* qemu-system-gui libsixel-bin w3m-img sharutils freerdp2-x11 nscd debconf-utils iotop 'manpages-posix*' konsole lsof
  526.  
  527. +#
  528. +# sparse file (data+hole) tests
  529. +#
  530. +ksh93 tests/sparsefiles/testsparsefile1.ksh
  531. +
  532.  #
  533.  # EOF.
  534. diff --git a/tests/sparsefiles/testsparsefile1.ksh b/tests/sparsefiles/testsparsefile1.ksh
  535. new file mode 100644
  536. index 0000000..ea43f74
  537. --- /dev/null
  538. +++ b/tests/sparsefiles/testsparsefile1.ksh
  539. @@ -0,0 +1,118 @@
  540. +#!/bin/ksh93
  541. +
  542. +#
  543. +# MIT License
  544. +#
  545. +# Copyright (c) 2025 Roland Mainz <roland.mainz@nrubsig.org>
  546. +#
  547. +# Permission is hereby granted, free of charge, to any person obtaining a copy
  548. +# of this software and associated documentation files (the "Software"), to deal
  549. +# in the Software without restriction, including without limitation the rights
  550. +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  551. +# copies of the Software, and to permit persons to whom the Software is
  552. +# furnished to do so, subject to the following conditions:
  553. +#
  554. +# The above copyright notice and this permission notice shall be included in all
  555. +# copies or substantial portions of the Software.
  556. +#
  557. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  558. +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  559. +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  560. +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  561. +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  562. +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  563. +# SOFTWARE.
  564. +#
  565. +
  566. +#
  567. +# testsparsefile1.ksh - simple sparsefile test
  568. +#
  569. +# Written by Roland Mainz <roland.mainz@nrubsig.org>
  570. +#
  571. +
  572. +
  573. +
  574. +PATH='/bin:/usr/bin'
  575. +
  576. +builtin rm
  577. +
  578. +function test_sparsefile1
  579. +{
  580. +    set -o errexit
  581. +    set -o nounset
  582. +    #set -o xtrace
  583. +
  584. +    compound c
  585. +
  586. +    integer c.fsblocksize=$1
  587. +    integer c.start_data_section=$2
  588. +    integer c.end_data_section=$3
  589. +
  590. +    integer i
  591. +    compound -a c.filecontent
  592. +
  593. +    #
  594. +    # generate sparse file layout+contents
  595. +    #
  596. +    for (( i=c.start_data_section ; i < c.end_data_section ; i++ )) ; do
  597. +        c.filecontent[$i]=(
  598. +            integer pos=i*1024*c.fsblocksize
  599. +            typeset data="$(printf "#block %d*1024*%d\n" i c.fsblocksize)"
  600. +        )
  601. +    done
  602. +
  603. +
  604. +    #
  605. +    # generate sparse file
  606. +    #
  607. +    rm -f 'mysparsefile'
  608. +    printf '' >'mysparsefile' # trunc
  609. +
  610. +    for i in ${!c.filecontent[@]} ; do
  611. +        dd of='mysparsefile' bs=1 conv=notrunc seek=${c.filecontent[$i].pos} status=none <<<"${c.filecontent[$i].data}"
  612. +    done
  613. +
  614. +
  615. +    #
  616. +    # print results
  617. +    #
  618. +    printf '#\n# Results:\n#\n'
  619. +
  620. +    ls -l mysparsefile
  621. +
  622. +    /cygdrive/c/Windows/system32/fsutil sparse queryrange 'mysparsefile'
  623. +
  624. +    integer fsutil_num_data_sections="$(/cygdrive/c/Windows/system32/fsutil sparse queryrange 'mysparsefile' | wc -l)"
  625. +
  626. +
  627. +    #
  628. +    # test whether the file is OK
  629. +    #
  630. +    if (( fsutil_num_data_sections != (c.end_data_section-c.start_data_section) )) ; then
  631. +        printf "# TEST failed, found %d data sections, expceted %d\n" \
  632. +            fsutil_num_data_sections \
  633. +            $((c.end_data_section-c.start_data_section))
  634. +        return 1
  635. +    fi
  636. +
  637. +    printf "\n#\n# TEST OK, found %d data sections\n#\n" \
  638. +        fsutil_num_data_sections
  639. +    return 0
  640. +}
  641. +
  642. +
  643. +#
  644. +# main
  645. +#
  646. +set -o errexit
  647. +test_sparsefile1 1024 0 4
  648. +test_sparsefile1 1024 1 4
  649. +test_sparsefile1 1024 0 32
  650. +test_sparsefile1 1024 2 32
  651. +
  652. +# 512 does not work, as Win10 fsutil can only handle 64 data sections
  653. +# test_sparsefile1 1024 2 512
  654. +
  655. +printf '%s: All tests OK\n' "$0"
  656. +exit 0
  657. +# EOF.
  658. --
  659. 2.45.1

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