pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patches to add new winfileclone utility, lssparse cstyle, error codes+misc, 2025-04-23
Posted by Anonymous on Wed 23rd Apr 2025 18:09
raw | new post

  1. From f56681e82be7b69ae13503abe4431647872fff6c Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Tue, 22 Apr 2025 10:43:24 +0200
  4. Subject: [PATCH 1/6] sys: Increase |ReadAheadGranularity| to 64k to match
  5.  |CcSetReadAheadGranularity()| spec+fast networks
  6.  
  7. Increase |ReadAheadGranularity| to 64k to match
  8. |CcSetReadAheadGranularity()| spec and better match fast
  9. networks (>= 1000baseT).
  10.  
  11. |CcSetReadAheadGranularity()| says |ReadAheadGranularity| must be an
  12. even power of two and must be greater than or equal to |PAGE_SIZE|
  13. But mrxfcb.h defines |DEFAULT_READ_AHEAD_GRANULARITY| as
  14. |(0x08000)| (=32768), but |log2(32768)==15|, and |15| is an
  15. odd number, violating that rule.
  16.  
  17. We now use 2**16==64k here, per |CcSetReadAheadGranularity()|
  18. spec, and to better match much faster networks
  19. (|DEFAULT_READ_AHEAD_GRANULARITY| was defined when 10baseT was "normal",
  20. today in 2025 1000baseT is the new "normal").
  21.  
  22. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  23. ---
  24. sys/nfs41sys_mount.c | 27 ++++++++++++++++++++++++++-
  25.  1 file changed, 26 insertions(+), 1 deletion(-)
  26.  
  27. diff --git a/sys/nfs41sys_mount.c b/sys/nfs41sys_mount.c
  28. index 93a6d34..e672c0a 100644
  29. --- a/sys/nfs41sys_mount.c
  30. +++ b/sys/nfs41sys_mount.c
  31. @@ -1,6 +1,6 @@
  32.  /* NFSv4.1 client for Windows
  33.   * Copyright (C) 2012 The Regents of the University of Michigan
  34. - * Copyright (C) 2023-2024 Roland Mainz <roland.mainz@nrubsig.org>
  35. + * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  36.   *
  37.   * Olga Kornievskaia <aglo@umich.edu>
  38.   * Casey Bodley <cbodley@umich.edu>
  39. @@ -1197,6 +1197,31 @@ NTSTATUS nfs41_CreateVNetRoot(
  40.          }
  41.      }
  42.      pNetRootContext->nfs41d_version = nfs41d_version;
  43. +
  44. +    DbgP("default pNetRoot->DiskParameters=("
  45. +        "ClusterSize=%lu, "
  46. +        "ReadAheadGranularity=%lu, "
  47. +        "LockThrottlingParameters=(Increment=%lu MaximumDelay=%lu)"
  48. +        ")\n",
  49. +        pNetRoot->DiskParameters.ClusterSize,
  50. +        pNetRoot->DiskParameters.ReadAheadGranularity,
  51. +        pNetRoot->DiskParameters.LockThrottlingParameters.Increment,
  52. +        pNetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
  53. +
  54. +    /*
  55. +     * Windows bug(?!):
  56. +     * |CcSetReadAheadGranularity()| says |ReadAheadGranularity|
  57. +     * must be an even power of two and must be greater than
  58. +     * or equal to PAGE_SIZE
  59. +     * But mrxfcb.h defines |DEFAULT_READ_AHEAD_GRANULARITY| as
  60. +     * |(0x08000)| (=32768), but |log2(32768)==15|, and |15| is an
  61. +     * odd number, violating that rule.
  62. +     *
  63. +     * We now use 2**16==64k here, per |CcSetReadAheadGranularity()|
  64. +     * spec
  65. +     */
  66. +    pNetRoot->DiskParameters.ReadAheadGranularity = 64*1024*1024;
  67. +
  68.  #ifdef DEBUG_MOUNT
  69.      DbgP("Saving new session 0x%p\n", pVNetRootContext->session);
  70.  #endif
  71. --
  72. 2.45.1
  73.  
  74. From 0d09d27dd2729233d5e6fcd3121ca88f7ceaeba1 Mon Sep 17 00:00:00 2001
  75. From: Roland Mainz <roland.mainz@nrubsig.org>
  76. Date: Wed, 23 Apr 2025 10:10:00 +0200
  77. Subject: [PATCH 2/6] daemon,sys: Fix return codes for opening file as dir and
  78.  opening dir as file
  79.  
  80. Fix return codes for opening file as dir and opening dir as file,
  81. based on the |NTSTATUS| values returned by NTFS+SMB.
  82.  
  83. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  84. ---
  85. daemon/open.c            | 17 +++++++++++++++--
  86.  sys/nfs41sys_debug.c     |  7 +++++--
  87.  sys/nfs41sys_openclose.c |  8 ++++++--
  88.  3 files changed, 26 insertions(+), 6 deletions(-)
  89.  
  90. diff --git a/daemon/open.c b/daemon/open.c
  91. index 1996e98..905ed5d 100644
  92. --- a/daemon/open.c
  93. +++ b/daemon/open.c
  94. @@ -903,7 +903,13 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
  95.              if (args->create_opts & FILE_NON_DIRECTORY_FILE) {
  96.                  DPRINTF(1, ("trying to open directory '%s' as a file\n",
  97.                      state->path.path));
  98. -                status = ERROR_DIRECTORY;
  99. +                /*
  100. +                 * Notes:
  101. +                 * - NTFS+SMB returns |STATUS_FILE_IS_A_DIRECTORY|
  102. +                 * - See |map_open_errors()| for the mapping to
  103. +                 * |STATUS_*|
  104. +                 */
  105. +                status = ERROR_DIRECTORY_NOT_SUPPORTED;
  106.                  goto out_free_state;
  107.              }
  108.          } else if (info.type == NF4REG) {
  109. @@ -911,7 +917,14 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
  110.              if (args->create_opts & FILE_DIRECTORY_FILE) {
  111.                  DPRINTF(1, ("trying to open file '%s' as a directory\n",
  112.                      state->path.path));
  113. -                status = ERROR_BAD_FILE_TYPE;
  114. +                /*
  115. +                 * Notes:
  116. +                 * - SMB returns |STATUS_OBJECT_TYPE_MISMATCH|
  117. +                 * while NTFS returns |STATUS_NOT_A_DIRECTORY|
  118. +                 * - See |map_open_errors()| for the mapping to
  119. +                 * |STATUS_*|
  120. +                 */
  121. +                status = ERROR_DIRECTORY;
  122.                  goto out_free_state;
  123.              }
  124.          } else if (info.type == NF4LNK) {
  125. diff --git a/sys/nfs41sys_debug.c b/sys/nfs41sys_debug.c
  126. index 4e0dac7..ed88ca7 100644
  127. --- a/sys/nfs41sys_debug.c
  128. +++ b/sys/nfs41sys_debug.c
  129. @@ -734,12 +734,15 @@ void print_open_error(int on, int status)
  130.      case ERROR_TOO_MANY_LINKS:
  131.          DbgP("[ERROR] nfs41_Create: STATUS_TOO_MANY_LINKS\n");
  132.          break;
  133. -    case ERROR_DIRECTORY:
  134. +    case ERROR_DIRECTORY_NOT_SUPPORTED:
  135.          DbgP("[ERROR] nfs41_Create: STATUS_FILE_IS_A_DIRECTORY\n");
  136.          break;
  137. -    case ERROR_BAD_FILE_TYPE:
  138. +    case ERROR_DIRECTORY:
  139.          DbgP("[ERROR] nfs41_Create: STATUS_NOT_A_DIRECTORY\n");
  140.          break;
  141. +    case ERROR_BAD_FILE_TYPE:
  142. +        DbgP("[ERROR] nfs41_Create: STATUS_BAD_FILE_TYPE\n");
  143. +        break;
  144.      default:
  145.          DbgP("[ERROR] nfs41_Create: STATUS_INSUFFICIENT_RESOURCES\n");
  146.          break;
  147. diff --git a/sys/nfs41sys_openclose.c b/sys/nfs41sys_openclose.c
  148. index d0cc36f..ad1bd53 100644
  149. --- a/sys/nfs41sys_openclose.c
  150. +++ b/sys/nfs41sys_openclose.c
  151. @@ -408,8 +408,12 @@ NTSTATUS map_open_errors(
  152.      case ERROR_SHARING_VIOLATION:       return STATUS_SHARING_VIOLATION;
  153.      case ERROR_REPARSE:                 return STATUS_REPARSE;
  154.      case ERROR_TOO_MANY_LINKS:          return STATUS_TOO_MANY_LINKS;
  155. -    case ERROR_DIRECTORY:               return STATUS_FILE_IS_A_DIRECTORY;
  156. -    case ERROR_BAD_FILE_TYPE:           return STATUS_NOT_A_DIRECTORY;
  157. +    case ERROR_INVALID_PARAMETER:       return STATUS_INVALID_PARAMETER;
  158. +    /* See |handle_open()| for |ERROR_DIRECTORY| */
  159. +    case ERROR_DIRECTORY:               return STATUS_NOT_A_DIRECTORY;
  160. +    /* See |handle_open()| for |ERROR_DIRECTORY_NOT_SUPPORTED| */
  161. +    case ERROR_DIRECTORY_NOT_SUPPORTED: return STATUS_FILE_IS_A_DIRECTORY;
  162. +    case ERROR_BAD_FILE_TYPE:           return STATUS_BAD_FILE_TYPE;
  163.      case ERROR_DISK_FULL:               return STATUS_DISK_FULL;
  164.      case ERROR_DISK_QUOTA_EXCEEDED:     return STATUS_DISK_QUOTA_EXCEEDED;
  165.      case ERROR_FILE_TOO_LARGE:          return STATUS_FILE_TOO_LARGE;
  166. --
  167. 2.45.1
  168.  
  169. From a5164373f56f62ed7d3c6bdd64a40441c2ef9ea1 Mon Sep 17 00:00:00 2001
  170. From: Roland Mainz <roland.mainz@nrubsig.org>
  171. Date: Wed, 23 Apr 2025 10:12:14 +0200
  172. Subject: [PATCH 3/6] daemon: |nfs_to_windows_error()| should map
  173.  |NFS4ERR_NOTDIR|+|NFS4ERR_ISDIR| to independent error codes
  174.  
  175. |nfs_to_windows_error()| should map |NFS4ERR_NOTDIR|+|NFS4ERR_ISDIR|
  176. to independent error codes.
  177.  
  178. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  179. ---
  180. daemon/util.c | 22 ++++++++++++++++++----
  181.  1 file changed, 18 insertions(+), 4 deletions(-)
  182.  
  183. diff --git a/daemon/util.c b/daemon/util.c
  184. index bb5bc88..10bdce6 100644
  185. --- a/daemon/util.c
  186. +++ b/daemon/util.c
  187. @@ -1,5 +1,6 @@
  188.  /* NFSv4.1 client for Windows
  189. - * Copyright (C) 2012 The Regents of the University of Michigan
  190. + * Copyright (C) 2012 The Regents of the University of Michigan
  191. + * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  192.   *
  193.   * Olga Kornievskaia <aglo@umich.edu>
  194.   * Casey Bodley <cbodley@umich.edu>
  195. @@ -213,9 +214,22 @@ int nfs_to_windows_error(int status, int default_error)
  196.      case NFS4ERR_BADCHAR:
  197.      case NFS4ERR_BADNAME:       return ERROR_INVALID_NAME;
  198.  
  199. -    case NFS4ERR_NOTDIR:
  200. -    case NFS4ERR_ISDIR:
  201. -    case NFS4ERR_SYMLINK:
  202. +    /*
  203. +     * |NFS4ERR_NOTDIR| - The current (or saved) filehandle
  204. +     * designates an object that is not a directory for an operation
  205. +     * in which a directory is required.
  206. +     * |ERROR_DIRECTORY| - The directory name is invalid.
  207. +     */
  208. +    case NFS4ERR_NOTDIR:        return ERROR_DIRECTORY;
  209. +    /*
  210. +     * |NFS4ERR_ISDIR| - The current or saved filehandle designates
  211. +     * a directory when the current operation does not allow a
  212. +     * directory to be accepted as the target of this operation.
  213. +     * |ERROR_DIRECTORY_NOT_SUPPORTED| - An operation is not supported
  214. +     * on a directory.
  215. +     */
  216. +    case NFS4ERR_ISDIR:         return ERROR_DIRECTORY_NOT_SUPPORTED;
  217. +    case NFS4ERR_SYMLINK:       return ERROR_INVALID_PARAMETER;
  218.      case NFS4ERR_WRONG_TYPE:    return ERROR_INVALID_PARAMETER;
  219.  
  220.      case NFS4ERR_EXPIRED:
  221. --
  222. 2.45.1
  223.  
  224. From 55d75f3acb287309a0b0a72e6b2e30e6b6c9f6a5 Mon Sep 17 00:00:00 2001
  225. From: Roland Mainz <roland.mainz@nrubsig.org>
  226. Date: Wed, 23 Apr 2025 10:26:49 +0200
  227. Subject: [PATCH 4/6] daemon,sys: Error codes for non-empty dirs should use
  228.  |ERROR_DIR_NOT_EMPTY|
  229.  
  230. Error codes for non-empty dirs should use |ERROR_DIR_NOT_EMPTY|,
  231. not |ERROR_NOT_EMPTY|.
  232.  
  233. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  234. ---
  235. daemon/util.c            | 4 ++--
  236.  sys/nfs41sys_fileinfo.c  | 2 +-
  237.  sys/nfs41sys_openclose.c | 2 +-
  238.  sys/nfs41sys_symlink.c   | 2 +-
  239.  4 files changed, 5 insertions(+), 5 deletions(-)
  240.  
  241. diff --git a/daemon/util.c b/daemon/util.c
  242. index 10bdce6..a9ddbd4 100644
  243. --- a/daemon/util.c
  244. +++ b/daemon/util.c
  245. @@ -199,7 +199,7 @@ int nfs_to_windows_error(int status, int default_error)
  246.      case NFS4ERR_MLINK:         return ERROR_TOO_MANY_LINKS;
  247.      case NFS4ERR_NAMETOOLONG:   return ERROR_FILENAME_EXCED_RANGE;
  248.      case NFS4ERR_STALE:         return ERROR_NETNAME_DELETED;
  249. -    case NFS4ERR_NOTEMPTY:      return ERROR_NOT_EMPTY;
  250. +    case NFS4ERR_NOTEMPTY:      return ERROR_DIR_NOT_EMPTY;
  251.      case NFS4ERR_DENIED:        return ERROR_LOCK_FAILED;
  252.      case NFS4ERR_NOTSUPP:       return ERROR_NOT_SUPPORTED;
  253.      case NFS4ERR_TOOSMALL:      return ERROR_BUFFER_OVERFLOW;
  254. @@ -255,7 +255,7 @@ int map_symlink_errors(int status)
  255.      case NFS4ERR_BADNAME:       return ERROR_INVALID_REPARSE_DATA;
  256.      case NFS4ERR_WRONG_TYPE:    return ERROR_NOT_A_REPARSE_POINT;
  257.      case NFS4ERR_ACCESS:        return ERROR_ACCESS_DENIED;
  258. -    case NFS4ERR_NOTEMPTY:      return ERROR_NOT_EMPTY;
  259. +    case NFS4ERR_NOTEMPTY:      return ERROR_DIR_NOT_EMPTY;
  260.      default: return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  261.      }
  262.  }
  263. diff --git a/sys/nfs41sys_fileinfo.c b/sys/nfs41sys_fileinfo.c
  264. index 4c7dceb..e5bd1a0 100644
  265. --- a/sys/nfs41sys_fileinfo.c
  266. +++ b/sys/nfs41sys_fileinfo.c
  267. @@ -511,7 +511,7 @@ NTSTATUS map_setfile_error(
  268.  {
  269.      switch (error) {
  270.      case NO_ERROR:                      return STATUS_SUCCESS;
  271. -    case ERROR_NOT_EMPTY:               return STATUS_DIRECTORY_NOT_EMPTY;
  272. +    case ERROR_DIR_NOT_EMPTY:           return STATUS_DIRECTORY_NOT_EMPTY;
  273.      case ERROR_FILE_EXISTS:             return STATUS_OBJECT_NAME_COLLISION;
  274.      case ERROR_FILE_NOT_FOUND:          return STATUS_OBJECT_NAME_NOT_FOUND;
  275.      case ERROR_PATH_NOT_FOUND:          return STATUS_OBJECT_PATH_NOT_FOUND;
  276. diff --git a/sys/nfs41sys_openclose.c b/sys/nfs41sys_openclose.c
  277. index ad1bd53..9334701 100644
  278. --- a/sys/nfs41sys_openclose.c
  279. +++ b/sys/nfs41sys_openclose.c
  280. @@ -1104,7 +1104,7 @@ NTSTATUS map_close_errors(
  281.      case NO_ERROR:              return STATUS_SUCCESS;
  282.      case ERROR_FILE_NOT_FOUND:  return STATUS_NO_SUCH_FILE;
  283.      case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED;
  284. -    case ERROR_NOT_EMPTY:       return STATUS_DIRECTORY_NOT_EMPTY;
  285. +    case ERROR_DIR_NOT_EMPTY:   return STATUS_DIRECTORY_NOT_EMPTY;
  286.      case ERROR_FILE_INVALID:    return STATUS_FILE_INVALID;
  287.      case ERROR_DISK_FULL:       return STATUS_DISK_FULL;
  288.      case ERROR_DISK_QUOTA_EXCEEDED: return STATUS_DISK_QUOTA_EXCEEDED;
  289. diff --git a/sys/nfs41sys_symlink.c b/sys/nfs41sys_symlink.c
  290. index ead2e96..fffcde7 100644
  291. --- a/sys/nfs41sys_symlink.c
  292. +++ b/sys/nfs41sys_symlink.c
  293. @@ -148,7 +148,7 @@ NTSTATUS map_symlink_errors(
  294.      case ERROR_INVALID_REPARSE_DATA: return STATUS_IO_REPARSE_DATA_INVALID;
  295.      case ERROR_NOT_A_REPARSE_POINT: return STATUS_NOT_A_REPARSE_POINT;
  296.      case ERROR_ACCESS_DENIED:       return STATUS_ACCESS_DENIED;
  297. -    case ERROR_NOT_EMPTY:           return STATUS_DIRECTORY_NOT_EMPTY;
  298. +    case ERROR_DIR_NOT_EMPTY:       return STATUS_DIRECTORY_NOT_EMPTY;
  299.      case ERROR_OUTOFMEMORY:         return STATUS_INSUFFICIENT_RESOURCES;
  300.      case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;
  301.      case STATUS_BUFFER_TOO_SMALL:
  302. --
  303. 2.45.1
  304.  
  305. From a438c1dc21cec85f1f93556006be6c009ffb8436 Mon Sep 17 00:00:00 2001
  306. From: Roland Mainz <roland.mainz@nrubsig.org>
  307. Date: Wed, 23 Apr 2025 12:03:54 +0200
  308. Subject: [PATCH 5/6] tests: Make lssparse cstyle-clean
  309.  
  310. Make lssparse cstyle-clean.
  311.  
  312. See https://github.com/illumos/illumos-gate/blob/master/usr/src/tools/scripts/cstyle.pl
  313. for the cstyle utility used by UNIX/Solaris/Illumos
  314.  
  315. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  316. ---
  317. tests/lssparse/lssparse.c | 392 ++++++++++++++++++++------------------
  318.  1 file changed, 203 insertions(+), 189 deletions(-)
  319.  
  320. diff --git a/tests/lssparse/lssparse.c b/tests/lssparse/lssparse.c
  321. index 399ac75..ae1c73e 100644
  322. --- a/tests/lssparse/lssparse.c
  323. +++ b/tests/lssparse/lssparse.c
  324. @@ -11,8 +11,8 @@
  325.   * copies of the Software, and to permit persons to whom the Software is
  326.   * furnished to do so, subject to the following conditions:
  327.   *
  328. - * The above copyright notice and this permission notice shall be included in all
  329. - * copies or substantial portions of the Software.
  330. + * The above copyright notice and this permission notice shall be included in
  331. + * all copies or substantial portions of the Software.
  332.   *
  333.   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  334.   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  335. @@ -28,6 +28,10 @@
  336.   *
  337.   * Written by Roland Mainz <roland.mainz@nrubsig.org>
  338.   */
  339. +/*
  340. + * All changes must pass
  341. + * illumos-gate/blob/master/usr/src/tools/scripts/cstyle.pl
  342. + */
  343.  
  344.  #include <stdio.h>
  345.  #include <stdlib.h>
  346. @@ -37,17 +41,18 @@
  347.  #include <unistd.h>
  348.  #include <errno.h>
  349.  
  350. -#define EXIT_USAGE (2)
  351. +#define        EXIT_USAGE      (2)
  352.  
  353.  static
  354. -void usage(const char *progname)
  355. +void
  356. +usage(const char *progname)
  357.  {
  358. -    (void)fprintf(stderr, "Usage: %s [-h] [-xdH] <sparse_file>\n"
  359. -        "  -h: Display this help message\n"
  360. -        "  -x: Print offsets in hexadecimal (base 16)\n"
  361. -        "  -d: Print offsets in decimal (base 10)\n"
  362. -        "  -H: Print hole information\n",
  363. -        progname);
  364. +       (void) fprintf(stderr, "Usage: %s [-h] [-xdH] <sparse_file>\n"
  365. +               "  -h: Display this help message\n"
  366. +               "  -x: Print offsets in hexadecimal (base 16)\n"
  367. +               "  -d: Print offsets in decimal (base 10)\n"
  368. +               "  -H: Print hole information\n",
  369. +               progname);
  370.  }
  371.  
  372.  typedef enum _printbase {
  373. @@ -55,186 +60,195 @@ typedef enum _printbase {
  374.      pb_dec = 2
  375.  } printbase;
  376.  
  377. -int main(int argc, char *argv[])
  378. +int
  379. +main(int argc, char *argv[])
  380.  {
  381. -    /* Arguments */
  382. -    const char *progname = argv[0];
  383. -    printbase pb = pb_hex;
  384. -    bool print_holes = false;
  385. -    const char *filename;
  386. -
  387. -    int retval;
  388. -    int opt;
  389. -    int fd;
  390. -
  391. -    size_t i;
  392. -    off_t offset = 0;
  393. -    off_t data_start;
  394. -    off_t hole_start;
  395. -    off_t hole_end;
  396. -    off_t file_size;
  397. -    off_t data_len;
  398. -    off_t hole_len;
  399. -
  400. -    while ((opt = getopt(argc, argv, "hxdH")) != -1) {
  401. -        switch (opt) {
  402. -            case '?':
  403. -            case 'h':
  404. -                usage(progname);
  405. -                return EXIT_USAGE;
  406. -            case 'x':
  407. -                pb = pb_hex;
  408. -                break;
  409. -            case 'd':
  410. -                pb = pb_dec;
  411. -                break;
  412. -            case 'H':
  413. -                print_holes = true;
  414. -                break;
  415. -            default:
  416. -                break;
  417. -        }
  418. -    }
  419. -
  420. -    if (optind >= argc) {
  421. -        usage(progname);
  422. -        return EXIT_USAGE;
  423. -    }
  424. -
  425. -    filename = argv[optind];
  426. -
  427. -    fd = open(filename, O_RDONLY);
  428. -    if (fd == -1) {
  429. -        (void)fprintf(stderr, "%s: Open file failed with [%s]\n",
  430. -            progname,
  431. -            strerror(errno));
  432. -        return EXIT_FAILURE;
  433. -    }
  434. -
  435. -    /* Get file size */
  436. -    file_size = lseek(fd, 0, SEEK_END);
  437. -    if (file_size == -1) {
  438. -        (void)fprintf(stderr, "%s: Cannot seek [%s]\n",
  439. -            progname,
  440. -            strerror(errno));
  441. -        return EXIT_FAILURE;
  442. -    }
  443. -    (void)lseek(fd, 0, SEEK_SET);
  444. -
  445. -
  446. -    /*
  447. -     * Loop over hole&&data sections
  448. -     *
  449. -     * This loop must handle:
  450. -     * - normal files with no holes
  451. -     * - sparse files which start with data
  452. -     * - sparse files which start with a hole
  453. -     * - sparse files with multiple holes
  454. -     * - sparse files which end with data
  455. -     * - sparse files which end with a hole
  456. -     *
  457. -     * Note we start with index |1| for compatibility
  458. -     * with SUN's original sparse file debuggung tools
  459. -     * and Win32's
  460. -     * $ /cygdrive/c/Windows/system32/fsutil sparse queryrange ... #
  461. -     * output
  462. -     */
  463. -#define LSSPARSE_START_INDEX 1
  464. -    for (i=LSSPARSE_START_INDEX ;;) {
  465. -        data_start = lseek(fd, offset, SEEK_DATA);
  466. -        if (data_start == -1)
  467. -            break;
  468. -        hole_start = lseek(fd, data_start, SEEK_HOLE);
  469. -
  470. -        if (hole_start == -1) {
  471. -            if (errno == ENXIO) {
  472. -                /* No more holes ? Use file site as pos of next hole */
  473. -                hole_start = file_size;
  474. -            } else {
  475. -                (void)fprintf(stderr,
  476. -                    "%s: lseek(..., SEEK_HOLE, ...) failed with [%s]\n",
  477. -                    progname,
  478. -                    strerror(errno));
  479. -                    retval = EXIT_FAILURE;
  480. -                goto done;
  481. -            }
  482. -        }
  483. -
  484. -        if (print_holes &&
  485. -            (i == LSSPARSE_START_INDEX) && (data_start > 0)) {
  486. -            (void)printf((pb == pb_hex)?
  487. -                "Hole range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
  488. -                "Hole range[%ld]: offset=%lld,\tlength=%lld\n",
  489. -                (long)i,
  490. -                (long long)0,
  491. -                (long long)data_start);
  492. -            i++;
  493. -        }
  494. -
  495. -        data_len = hole_start - data_start;
  496. -
  497. -        (void)printf((pb == pb_hex)?
  498. -            "Data range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
  499. -            "Data range[%ld]: offset=%lld,\tlength=%lld\n",
  500. -            (long)i,
  501. -            (long long)data_start,
  502. -            (long long)data_len);
  503. -        i++;
  504. -
  505. -        hole_end = lseek(fd, hole_start, SEEK_DATA);
  506. -
  507. -        if (hole_end == -1) {
  508. -            if (errno == ENXIO) {
  509. -                /* No more holes ? */
  510. -                hole_end = file_size;
  511. -            } else {
  512. -                (void)fprintf(stderr,
  513. -                    "%s: lseek(..., SEEK_DATA, ...) failed with [%s]\n",
  514. -                    progname,
  515. -                    strerror(errno));
  516. -                retval = EXIT_FAILURE;
  517. -                goto done;
  518. -            }
  519. -        }
  520. -
  521. -        hole_len = hole_end - hole_start;
  522. -
  523. -        if (print_holes && (hole_len > 0LL)) {
  524. -            (void)printf((pb == pb_hex)?
  525. -                "Hole range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
  526. -                "Hole range[%ld]: offset=%lld,\tlength=%lld\n",
  527. -                (long)i,
  528. -                (long long)hole_start,
  529. -                (long long)hole_len);
  530. -            i++;
  531. -        }
  532. -
  533. -        offset = hole_end;
  534. -    }
  535. -
  536. -    if ((data_start == -1) && (errno == ENXIO) && (offset == 0)) {
  537. -        if (print_holes) {
  538. -            (void)printf((pb == pb_hex)?
  539. -                "Hole range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
  540. -                "Hole range[%ld]: offset=%lld,\tlength=%lld\n",
  541. -                (long)LSSPARSE_START_INDEX,
  542. -                (long long)0LL,
  543. -                (long long)file_size);
  544. -        }
  545. -
  546. -        retval = EXIT_SUCCESS;
  547. -    } else if ((data_start == -1) && (errno != ENXIO)) {
  548. -        (void)fprintf(stderr,
  549. -            "%s: lseek(..., SEEK_DATA, ...) failed with [%s]\n",
  550. -            progname,
  551. -            strerror(errno));
  552. -            retval = EXIT_FAILURE;
  553. -    }
  554. -    else {
  555. -        retval = EXIT_SUCCESS;
  556. -    }
  557. +       /* Arguments */
  558. +       const char *progname = argv[0];
  559. +       printbase pb = pb_hex;
  560. +       bool print_holes = false;
  561. +       const char *filename;
  562. +
  563. +       int retval;
  564. +       int opt;
  565. +       int fd;
  566. +
  567. +       size_t i;
  568. +       off_t offset = 0;
  569. +       off_t data_start;
  570. +       off_t hole_start;
  571. +       off_t hole_end;
  572. +       off_t file_size;
  573. +       off_t data_len;
  574. +       off_t hole_len;
  575. +
  576. +       while ((opt = getopt(argc, argv, "hxdH")) != -1) {
  577. +               switch (opt) {
  578. +                       case '?':
  579. +                       case 'h':
  580. +                               usage(progname);
  581. +                               return (EXIT_USAGE);
  582. +                       case 'x':
  583. +                               pb = pb_hex;
  584. +                               break;
  585. +                       case 'd':
  586. +                               pb = pb_dec;
  587. +                               break;
  588. +                       case 'H':
  589. +                               print_holes = true;
  590. +                               break;
  591. +                       default:
  592. +                               break;
  593. +               }
  594. +       }
  595. +
  596. +       if (optind >= argc) {
  597. +               usage(progname);
  598. +               return (EXIT_USAGE);
  599. +       }
  600. +
  601. +       filename = argv[optind];
  602. +
  603. +       fd = open(filename, O_RDONLY);
  604. +       if (fd == -1) {
  605. +               (void) fprintf(stderr, "%s: Open file failed with [%s]\n",
  606. +                       progname,
  607. +                       strerror(errno));
  608. +               return (EXIT_FAILURE);
  609. +       }
  610. +
  611. +       /* Get file size */
  612. +       file_size = lseek(fd, 0, SEEK_END);
  613. +       if (file_size == -1) {
  614. +               (void) fprintf(stderr, "%s: Cannot seek [%s]\n",
  615. +               progname,
  616. +               strerror(errno));
  617. +               return (EXIT_FAILURE);
  618. +       }
  619. +       (void) lseek(fd, 0, SEEK_SET);
  620. +
  621. +
  622. +       /*
  623. +        * Loop over hole&&data sections
  624. +        *
  625. +        * This loop must handle:
  626. +        * - normal files with no holes
  627. +        * - sparse files which start with data
  628. +        * - sparse files which start with a hole
  629. +        * - sparse files with multiple holes
  630. +        * - sparse files which end with data
  631. +        * - sparse files which end with a hole
  632. +        *
  633. +        * Note we start with index |1| for compatibility
  634. +        * with SUN's original sparse file debuggung tools
  635. +        * and Win32's
  636. +        * $ /cygdrive/c/Windows/system32/fsutil sparse queryrange ... #
  637. +        * output
  638. +        */
  639. +#define        LSSPARSE_START_INDEX    1
  640. +       for (i = LSSPARSE_START_INDEX ; ; ) {
  641. +               data_start = lseek(fd, offset, SEEK_DATA);
  642. +               if (data_start == -1)
  643. +                       break;
  644. +               hole_start = lseek(fd, data_start, SEEK_HOLE);
  645. +
  646. +               if (hole_start == -1) {
  647. +                       if (errno == ENXIO) {
  648. +                               /*
  649. +                                * No more holes ? Use file site as pos of
  650. +                                * next hole
  651. +                                */
  652. +                               hole_start = file_size;
  653. +               } else {
  654. +                       (void) fprintf(stderr,
  655. +                               "%s: "
  656. +                               "lseek(..., SEEK_HOLE, ...) failed with [%s]\n",
  657. +                               progname,
  658. +                               strerror(errno));
  659. +                               retval = EXIT_FAILURE;
  660. +                               goto done;
  661. +                       }
  662. +               }
  663. +
  664. +               if (print_holes &&
  665. +                       (i == LSSPARSE_START_INDEX) && (data_start > 0)) {
  666. +                       (void) printf((pb == pb_hex)?
  667. +                               "Hole range[%ld]: "
  668. +                               "offset=0x%llx,\tlength=0x%llx\n":
  669. +                               "Hole range[%ld]: "
  670. +                               "offset=%lld,\tlength=%lld\n",
  671. +                               (long)i,
  672. +                               (long long)0,
  673. +                               (long long)data_start);
  674. +                       i++;
  675. +               }
  676. +
  677. +               data_len = hole_start - data_start;
  678. +
  679. +               (void) printf((pb == pb_hex)?
  680. +                       "Data range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
  681. +                       "Data range[%ld]: offset=%lld,\tlength=%lld\n",
  682. +                       (long)i,
  683. +                       (long long)data_start,
  684. +                       (long long)data_len);
  685. +               i++;
  686. +
  687. +               hole_end = lseek(fd, hole_start, SEEK_DATA);
  688. +
  689. +               if (hole_end == -1) {
  690. +                       if (errno == ENXIO) {
  691. +                       /* No more holes ? */
  692. +                       hole_end = file_size;
  693. +               } else {
  694. +                       (void) fprintf(stderr,
  695. +                               "%s: "
  696. +                               "lseek(..., SEEK_DATA, ...) failed with [%s]\n",
  697. +                               progname,
  698. +                               strerror(errno));
  699. +                       retval = EXIT_FAILURE;
  700. +                       goto done;
  701. +               }
  702. +       }
  703. +
  704. +       hole_len = hole_end - hole_start;
  705. +
  706. +       if (print_holes && (hole_len > 0LL)) {
  707. +               (void) printf((pb == pb_hex)?
  708. +                       "Hole range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
  709. +                       "Hole range[%ld]: offset=%lld,\tlength=%lld\n",
  710. +                       (long)i,
  711. +                       (long long)hole_start,
  712. +                       (long long)hole_len);
  713. +               i++;
  714. +       }
  715. +
  716. +       offset = hole_end;
  717. +       }
  718. +
  719. +       if ((data_start == -1) && (errno == ENXIO) && (offset == 0)) {
  720. +               if (print_holes) {
  721. +                       (void) printf((pb == pb_hex)?
  722. +                               "Hole range[%ld]: "
  723. +                               "offset=0x%llx,\tlength=0x%llx\n":
  724. +                               "Hole range[%ld]: "
  725. +                               "offset=%lld,\tlength=%lld\n",
  726. +                               (long)LSSPARSE_START_INDEX,
  727. +                               (long long)0LL,
  728. +                               (long long)file_size);
  729. +                       }
  730. +
  731. +               retval = EXIT_SUCCESS;
  732. +       } else if ((data_start == -1) && (errno != ENXIO)) {
  733. +               (void) fprintf(stderr,
  734. +                       "%s: lseek(..., SEEK_DATA, ...) failed with [%s]\n",
  735. +                       progname,
  736. +                       strerror(errno));
  737. +                       retval = EXIT_FAILURE;
  738. +       } else {
  739. +               retval = EXIT_SUCCESS;
  740. +       }
  741.  
  742.  done:
  743. -    (void)close(fd);
  744. -    return retval;
  745. +       (void) close(fd);
  746. +       return (retval);
  747.  }
  748. --
  749. 2.45.1
  750.  
  751. From cf2549ca6d0b9c201de9daec6c3baf9fbcb97ec5 Mon Sep 17 00:00:00 2001
  752. From: Roland Mainz <roland.mainz@nrubsig.org>
  753. Date: Wed, 23 Apr 2025 18:57:36 +0200
  754. Subject: [PATCH 6/6] cygwin,tests: Add winclonefile utility for block cloning
  755.  tests
  756.  
  757. Add winclonefile utility for block cloning tests.
  758.  
  759. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  760. ---
  761. cygwin/Makefile                   |   4 +
  762.  cygwin/Makefile.install           |   7 +
  763.  tests/winclonefile/Makefile       |  23 +++
  764.  tests/winclonefile/winclonefile.c | 251 ++++++++++++++++++++++++++++++
  765.  4 files changed, 285 insertions(+)
  766.  create mode 100644 tests/winclonefile/Makefile
  767.  create mode 100644 tests/winclonefile/winclonefile.c
  768.  
  769. diff --git a/cygwin/Makefile b/cygwin/Makefile
  770. index 9ae5b84..f2aadb4 100644
  771. --- a/cygwin/Makefile
  772. +++ b/cygwin/Makefile
  773. @@ -22,6 +22,7 @@ VS_BUILD_DIR64:=$(PROJECT_BASEDIR_DIR)/build.vc19/x64/Debug/
  774.  $(PROJECT_BASEDIR_DIR)/tests/ea/nfs_ea.exe \
  775.         $(PROJECT_BASEDIR_DIR)/tests/lssparse/lssparse.exe \
  776.         $(PROJECT_BASEDIR_DIR)/tests/winfsinfo1/winfsinfo.exe \
  777. +       $(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.exe \
  778.         $(PROJECT_BASEDIR_DIR)/tests/winsg/winsg.exe: build_testutils
  779.  
  780.  #
  781. @@ -66,6 +67,7 @@ build_testutils:
  782.         (cd "$(PROJECT_BASEDIR_DIR)/tests/ea" && make all)
  783.         (cd "$(PROJECT_BASEDIR_DIR)/tests/lssparse" && make all)
  784.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winfsinfo1" && make all)
  785. +       (cd "$(PROJECT_BASEDIR_DIR)/tests/winclonefile" && make all)
  786.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winsg" && make all)
  787.  
  788.  build: build_32bit_release build_32bit_debug build_64bit_release build_64bit_debug build_arm_64bit_debug build_testutils
  789. @@ -100,6 +102,7 @@ clean:
  790.         (cd "$(PROJECT_BASEDIR_DIR)/tests/ea" && make clean)
  791.         (cd "$(PROJECT_BASEDIR_DIR)/tests/lssparse" && make clean)
  792.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winfsinfo1" && make clean)
  793. +       (cd "$(PROJECT_BASEDIR_DIR)/tests/winclonefile" && make clean)
  794.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winsg" && make clean)
  795.  
  796.  installdest_util: \
  797. @@ -109,6 +112,7 @@ installdest_util: \
  798.         $(PROJECT_BASEDIR_DIR)/tests/ea/nfs_ea.exe \
  799.         $(PROJECT_BASEDIR_DIR)/tests/lssparse/lssparse.exe \
  800.         $(PROJECT_BASEDIR_DIR)/tests/winfsinfo1/winfsinfo.exe \
  801. +       $(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.exe \
  802.         $(PROJECT_BASEDIR_DIR)/tests/winsg/winsg.exe \
  803.         $(CYGWIN_MAKEFILE_DIR)/devel/msnfs41client.bash
  804.  
  805. diff --git a/cygwin/Makefile.install b/cygwin/Makefile.install
  806. index e274aa5..dcd6f13 100644
  807. --- a/cygwin/Makefile.install
  808. +++ b/cygwin/Makefile.install
  809. @@ -103,6 +103,13 @@ installdest:
  810.         else \
  811.                 (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && ln -sf winfsinfo.i686.exe winfsinfo.exe) \
  812.         fi
  813. +       cp "$(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/winclonefile.x86_64.exe
  814. +       cp "$(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.i686.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/winclonefile.i686.exe
  815. +       if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
  816. +               (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && ln -sf winclonefile.x86_64.exe winclonefile.exe) \
  817. +       else \
  818. +               (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && ln -sf winclonefile.i686.exe winclonefile.exe) \
  819. +       fi
  820.         cp "$(PROJECT_BASEDIR_DIR)/tests/lssparse/lssparse.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/lssparse.x86_64.exe
  821.         if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
  822.                 (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && ln -sf lssparse.x86_64.exe lssparse.exe) \
  823. diff --git a/tests/winclonefile/Makefile b/tests/winclonefile/Makefile
  824. new file mode 100644
  825. index 0000000..bf548b7
  826. --- /dev/null
  827. +++ b/tests/winclonefile/Makefile
  828. @@ -0,0 +1,23 @@
  829. +#
  830. +# Makefile for winclonefile
  831. +#
  832. +
  833. +# POSIX Makefile
  834. +
  835. +all: winclonefile.i686.exe winclonefile.x86_64.exe winclonefile.exe
  836. +
  837. +winclonefile.i686.exe: winclonefile.c
  838. +       clang -target i686-pc-windows-gnu -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -I../../include -g winclonefile.c -lntdll -o winclonefile.i686.exe
  839. +
  840. +winclonefile.x86_64.exe: winclonefile.c
  841. +       clang -target x86_64-pc-windows-gnu -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -I../../include -g winclonefile.c -lntdll -o winclonefile.x86_64.exe
  842. +
  843. +winclonefile.exe: winclonefile.x86_64.exe
  844. +       ln -s winclonefile.x86_64.exe winclonefile.exe
  845. +
  846. +clean:
  847. +       rm -fv \
  848. +               winclonefile.i686.exe \
  849. +               winclonefile.x86_64.exe \
  850. +               winclonefile.exe \
  851. +# EOF.
  852. diff --git a/tests/winclonefile/winclonefile.c b/tests/winclonefile/winclonefile.c
  853. new file mode 100644
  854. index 0000000..7d2d490
  855. --- /dev/null
  856. +++ b/tests/winclonefile/winclonefile.c
  857. @@ -0,0 +1,251 @@
  858. +
  859. +/*
  860. + * MIT License
  861. + *
  862. + * Copyright (c) 2024-2025 Roland Mainz <roland.mainz@nrubsig.org>
  863. + *
  864. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  865. + * of this software and associated documentation files (the "Software"), to deal
  866. + * in the Software without restriction, including without limitation the rights
  867. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  868. + * copies of the Software, and to permit persons to whom the Software is
  869. + * furnished to do so, subject to the following conditions:
  870. + *
  871. + * The above copyright notice and this permission notice shall be included in
  872. + * all copies or substantial portions of the Software.
  873. + *
  874. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  875. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  876. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  877. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  878. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  879. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  880. + * SOFTWARE.
  881. + */
  882. +
  883. +/*
  884. + * winclonefile.c - clone a file
  885. + *
  886. + * Written by Roland Mainz <roland.mainz@nrubsig.org>
  887. + */
  888. +
  889. +#define WIN32_LEAN_AND_MEAN 1
  890. +
  891. +#include <windows.h>
  892. +#include <winioctl.h>
  893. +#include <stdio.h>
  894. +
  895. +#define EXIT_USAGE (2)
  896. +
  897. +#if 1
  898. +/*
  899. + * MinGW include do not define |DUPLICATE_EXTENTS_DATA| yet,
  900. + * see https://github.com/mingw-w64/mingw-w64/issues/90
  901. + * ("[mingw-w64/mingw-w64] No |DUPLICATE_EXTENTS_DATA|/
  902. + * |DUPLICATE_EXTENTS_DATA_EX| in MinGW includes")
  903. + */
  904. +typedef struct _DUPLICATE_EXTENTS_DATA {
  905. +    HANDLE FileHandle;
  906. +    LARGE_INTEGER SourceFileOffset;
  907. +    LARGE_INTEGER TargetFileOffset;
  908. +    LARGE_INTEGER ByteCount;
  909. +} DUPLICATE_EXTENTS_DATA, *PDUPLICATE_EXTENTS_DATA;
  910. +#endif
  911. +
  912. +
  913. +void
  914. +PrintWin32Error(const char *functionName, DWORD lasterrCode)
  915. +{
  916. +    char *lpMsgBuf;
  917. +
  918. +    (void)FormatMessageA(
  919. +        FORMAT_MESSAGE_ALLOCATE_BUFFER |
  920. +        FORMAT_MESSAGE_FROM_SYSTEM |
  921. +        FORMAT_MESSAGE_IGNORE_INSERTS,
  922. +        NULL,
  923. +        lasterrCode,
  924. +        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  925. +        (LPSTR)&lpMsgBuf,
  926. +        0, NULL);
  927. +
  928. +    (void)fprintf(stderr,
  929. +        "%s failed with error %lu: %s\n",
  930. +        functionName,
  931. +        (unsigned long)lasterrCode,
  932. +        lpMsgBuf);
  933. +
  934. +    LocalFree(lpMsgBuf);
  935. +}
  936. +
  937. +int
  938. +main(int ac, char *av[])
  939. +{
  940. +    const char* srcFileName;
  941. +    const char* dstFileName;
  942. +    HANDLE hSrc = INVALID_HANDLE_VALUE;
  943. +    HANDLE hDst = INVALID_HANDLE_VALUE;
  944. +    BOOL bResult = FALSE;
  945. +    LARGE_INTEGER fileSize = { .QuadPart = 0LL };
  946. +    DUPLICATE_EXTENTS_DATA ded = {
  947. +        .FileHandle = INVALID_HANDLE_VALUE,
  948. +        .SourceFileOffset.QuadPart = 0LL,
  949. +        .TargetFileOffset.QuadPart = 0LL,
  950. +        .ByteCount.QuadPart = 0LL
  951. +    };
  952. +    DWORD bytesReturnedDummy = 0; /* dummy var */
  953. +
  954. +    if (ac != 3) {
  955. +        (void)fprintf(stderr, "Usage: %s <infile> <outfile>\n", av[0]);
  956. +        return (EXIT_USAGE);
  957. +    }
  958. +
  959. +    srcFileName = av[1];
  960. +    dstFileName = av[2];
  961. +
  962. +    (void)printf("# Attempting to clone existing file '%s' to '%s' "
  963. +        "using FSCTL_DUPLICATE_EXTENTS_TO_FILE...\n",
  964. +        srcFileName,
  965. +        dstFileName);
  966. +
  967. +    hSrc = CreateFileA(
  968. +        srcFileName,
  969. +        GENERIC_READ,
  970. +        FILE_SHARE_READ,
  971. +        NULL,
  972. +        OPEN_EXISTING,
  973. +        FILE_ATTRIBUTE_NORMAL,
  974. +        NULL);
  975. +
  976. +    if (hSrc == INVALID_HANDLE_VALUE) {
  977. +        PrintWin32Error("CreateFileA (source read)",
  978. +            GetLastError());
  979. +        goto cleanup;
  980. +    }
  981. +    (void)printf("# Successfully opened existing source file '%s'.\n",
  982. +        srcFileName);
  983. +
  984. +    bResult = GetFileSizeEx(hSrc, &fileSize);
  985. +    if (!bResult) {
  986. +        PrintWin32Error("GetFileSizeEx",
  987. +            GetLastError());
  988. +        goto cleanup;
  989. +    }
  990. +
  991. +    if (fileSize.QuadPart == 0LL) {
  992. +        (void)fprintf(stderr,
  993. +            "# [NOTE] Source file '%s' is empty, "
  994. +            "cloning will result in an empty file.\n",
  995. +            srcFileName);
  996. +    }
  997. +
  998. +    (void)printf("Source file size: %lld bytes.\n",
  999. +        fileSize.QuadPart);
  1000. +
  1001. +    /* Get cluster size */
  1002. +    FILE_STORAGE_INFO fsi = { 0 };
  1003. +    bResult = GetFileInformationByHandleEx(hSrc,
  1004. +        FileStorageInfo, &fsi, sizeof(fsi));
  1005. +    if (!bResult) {
  1006. +        PrintWin32Error("FileStorageInfo",
  1007. +            GetLastError());
  1008. +        goto cleanup;
  1009. +    }
  1010. +
  1011. +    unsigned long long srcClusterSize =
  1012. +        fsi.PhysicalBytesPerSectorForAtomicity;
  1013. +    (void)printf("src file cluster size=%llu\n", srcClusterSize);
  1014. +
  1015. +    hDst = CreateFileA(
  1016. +        dstFileName,
  1017. +        GENERIC_ALL,
  1018. +        FILE_SHARE_DELETE|FILE_SHARE_WRITE,
  1019. +        NULL,
  1020. +        CREATE_ALWAYS,
  1021. +        FILE_ATTRIBUTE_NORMAL,
  1022. +        NULL);
  1023. +
  1024. +    if (hDst == INVALID_HANDLE_VALUE) {
  1025. +        PrintWin32Error("CreateFileA (destination)",
  1026. +            GetLastError());
  1027. +        goto cleanup;
  1028. +    }
  1029. +
  1030. +    if (fileSize.QuadPart > 0LL) {
  1031. +        if (!SetFilePointerEx(hDst, fileSize, NULL, FILE_BEGIN)) {
  1032. +             PrintWin32Error("SetFilePointerEx (pre-allocate)",
  1033. +                GetLastError());
  1034. +             goto cleanup;
  1035. +        }
  1036. +
  1037. +        /* Sets the file size to the current position of the file pointer */
  1038. +        bResult = SetEndOfFile(hDst);
  1039. +        if (!bResult) {
  1040. +            PrintWin32Error("SetEndOfFile (pre-allocate)",
  1041. +                GetLastError());
  1042. +            goto cleanup;
  1043. +        }
  1044. +
  1045. +        /* Reset file pointer to pos 0 */
  1046. +        LARGE_INTEGER currentPos = { .QuadPart = 0LL };
  1047. +        SetFilePointerEx(hDst, currentPos, NULL, FILE_BEGIN);
  1048. +    }
  1049. +
  1050. +    ded.FileHandle = hSrc;
  1051. +    ded.SourceFileOffset.QuadPart = 0LL;
  1052. +    ded.TargetFileOffset.QuadPart = 0LL;
  1053. +    ded.ByteCount = fileSize;
  1054. +
  1055. +    /*
  1056. +     * |FSCTL_DUPLICATE_EXTENTS_TO_FILE| spec requires that the src size
  1057. +     * is rounded to the filesytem's cluster size
  1058. +     *
  1059. +     * FIXME: What about the size of the destination file ?
  1060. +     */
  1061. +    ded.ByteCount.QuadPart =
  1062. +        (ded.ByteCount.QuadPart+srcClusterSize) & ~(srcClusterSize-1);
  1063. +
  1064. +    (void)printf("# DeviceIoControl(FSCTL_DUPLICATE_EXTENTS_TO_FILE)\n");
  1065. +
  1066. +    bResult = DeviceIoControl(
  1067. +        hDst,
  1068. +        FSCTL_DUPLICATE_EXTENTS_TO_FILE,
  1069. +        &ded,
  1070. +        sizeof(ded),
  1071. +        NULL,
  1072. +        0,
  1073. +        &bytesReturnedDummy,
  1074. +        NULL);
  1075. +
  1076. +    if (!bResult) {
  1077. +        PrintWin32Error("DeviceIoControl(FSCTL_DUPLICATE_EXTENTS_TO_FILE)",
  1078. +            GetLastError());
  1079. +        goto cleanup;
  1080. +    }
  1081. +
  1082. +    (void)printf("# Successfully cloned '%s' to '%s'!\n",
  1083. +        srcFileName, dstFileName);
  1084. +
  1085. +
  1086. +cleanup:
  1087. +    if ((!bResult) && (hDst != INVALID_HANDLE_VALUE)) {
  1088. +        (void)printf("# Failure, deleting destination file...\n");
  1089. +
  1090. +        FILE_DISPOSITION_INFO di = { .DeleteFile = TRUE };
  1091. +        bResult = SetFileInformationByHandle(hDst,
  1092. +            FileDispositionInfo, &di, sizeof(di));
  1093. +        if (!bResult) {
  1094. +            PrintWin32Error("Delete destination file",
  1095. +                GetLastError());
  1096. +        }
  1097. +    }
  1098. +
  1099. +    (void)printf("# Cleaning up...\n");
  1100. +    if (hSrc != INVALID_HANDLE_VALUE) {
  1101. +        (void)CloseHandle(hSrc);
  1102. +    }
  1103. +    if (hDst != INVALID_HANDLE_VALUE) {
  1104. +        (void)CloseHandle(hDst);
  1105. +    }
  1106. +
  1107. +    return bResult ? EXIT_SUCCESS : EXIT_FAILURE;
  1108. +}
  1109. --
  1110. 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