pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patchs for Win32 named streams, cleanup, docs+misc, 2026-01-06
Posted by Anonymous on Tue 6th Jan 2026 13:25
raw | new post

  1. From 5ece03478f48a34d4a21ac2a1c42f1e53cca524a Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Tue, 6 Jan 2026 11:27:56 +0100
  4. Subject: [PATCH 1/6] daemon: Fix namecache updates for Windows streams
  5.  
  6. Fix namecache updates for Windows streams.
  7.  
  8. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  9. ---
  10. daemon/nfs41_ops.c | 25 ++++++++++++++++++-------
  11.  1 file changed, 18 insertions(+), 7 deletions(-)
  12.  
  13. diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c
  14. index cc650e9..066c036 100644
  15. --- a/daemon/nfs41_ops.c
  16. +++ b/daemon/nfs41_ops.c
  17. @@ -864,13 +864,18 @@ int nfs41_close(
  18.      if (compound_error(status = compound.res.status))
  19.          goto out;
  20.  
  21. -    if (info.type == NF4NAMEDATTR)
  22. -        goto out;
  23. +    bool update_cache = true;
  24. +    if ((info.type == NF4NAMEDATTR) && (is_stream_path_fh(file) == false)) {
  25. +        /* This should only happen for Windows EAs */
  26. +        update_cache = false;
  27. +    }
  28.  
  29. -    /* update the attributes of the parent directory */
  30. -    bitmap4_cpy(&info.attrmask, &getattr_res.obj_attributes.attrmask);
  31. -    nfs41_attr_cache_update(session_name_cache(session),
  32. -        file->fh.fileid, &info);
  33. +    if (update_cache) {
  34. +        /* update the attributes of the parent directory */
  35. +        bitmap4_cpy(&info.attrmask, &getattr_res.obj_attributes.attrmask);
  36. +        nfs41_attr_cache_update(session_name_cache(session),
  37. +            file->fh.fileid, &info);
  38. +    }
  39.  out:
  40.      return status;
  41.  }
  42. @@ -947,7 +952,13 @@ int nfs41_write(
  43.      if (compound_error(status = compound.res.status))
  44.          goto out;
  45.  
  46. -    if (stable != UNSTABLE4 && pinfo->type != NF4NAMEDATTR) {
  47. +    bool update_cache = (stable != UNSTABLE4);
  48. +    if ((pinfo->type == NF4NAMEDATTR) && (is_stream_path_fh(file) == false)) {
  49. +        /* This should only happen for Windows EAs */
  50. +        update_cache = false;
  51. +    }
  52. +
  53. +    if (update_cache) {
  54.          /* update the attribute cache */
  55.          bitmap4_cpy(&pinfo->attrmask, &getattr_res.obj_attributes.attrmask);
  56.          nfs41_attr_cache_update(session_name_cache(session),
  57. --
  58. 2.51.0
  59.  
  60. From 7e479297b7b17217b48e80f31824873da2424066 Mon Sep 17 00:00:00 2001
  61. From: Roland Mainz <roland.mainz@nrubsig.org>
  62. Date: Tue, 6 Jan 2026 12:06:01 +0100
  63. Subject: [PATCH 2/6] daemon: Unify |read_entire_dir()| implementations and
  64.  move it to util.c
  65.  
  66. Unify |read_entire_dir()| implementations and move it to daemon/util.c.
  67.  
  68. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  69. ---
  70. daemon/ea.c         |  95 +++-----------------------------------
  71.  daemon/util.c       |  92 ++++++++++++++++++++++++++++++++++++-
  72.  daemon/util.h       |  14 +++++-
  73.  daemon/winstreams.c | 108 ++++++--------------------------------------
  74.  4 files changed, 124 insertions(+), 185 deletions(-)
  75.  
  76. diff --git a/daemon/ea.c b/daemon/ea.c
  77. index be5ecac..b9c94c1 100644
  78. --- a/daemon/ea.c
  79. +++ b/daemon/ea.c
  80. @@ -1,6 +1,6 @@
  81.  /* NFSv4.1 client for Windows
  82.   * Copyright (C) 2012 The Regents of the University of Michigan
  83. - * Copyright (C) 2024-2025 Roland Mainz <roland.mainz@nrubsig.org>
  84. + * Copyright (C) 2024-2026 Roland Mainz <roland.mainz@nrubsig.org>
  85.   *
  86.   * Olga Kornievskaia <aglo@umich.edu>
  87.   * Casey Bodley <cbodley@umich.edu>
  88. @@ -302,91 +302,6 @@ out:
  89.      return status;
  90.  }
  91.  
  92. -#define READDIR_LEN_INITIAL 8192
  93. -#define READDIR_LEN_MIN 2048
  94. -
  95. -/* call readdir repeatedly to get a complete list of entries */
  96. -static int read_entire_dir(
  97. -    IN nfs41_session *session,
  98. -    IN nfs41_path_fh *eadir,
  99. -    OUT unsigned char **buffer_out,
  100. -    OUT uint32_t *length_out)
  101. -{
  102. -    nfs41_readdir_cookie cookie = { 0 };
  103. -    bitmap4 attr_request;
  104. -    nfs41_readdir_entry *last_entry;
  105. -    unsigned char *buffer;
  106. -    uint32_t buffer_len, len, total_len;
  107. -    bool_t eof;
  108. -    int status = NO_ERROR;
  109. -
  110. -    attr_request.count = 0; /* don't request attributes */
  111. -
  112. -    /* allocate the buffer for readdir entries */
  113. -    buffer_len = READDIR_LEN_INITIAL;
  114. -    buffer = calloc(1, buffer_len);
  115. -    if (buffer == NULL) {
  116. -        status = GetLastError();
  117. -        goto out;
  118. -    }
  119. -
  120. -    last_entry = NULL;
  121. -    total_len = 0;
  122. -    eof = FALSE;
  123. -
  124. -    while (!eof) {
  125. -        len = buffer_len - total_len;
  126. -        if (len < READDIR_LEN_MIN) {
  127. -            const ptrdiff_t diff = (unsigned char*)last_entry - buffer;
  128. -            /* realloc the buffer to fit more entries */
  129. -            unsigned char *tmp = realloc(buffer, (size_t)buffer_len * 2L);
  130. -            if (tmp == NULL) {
  131. -                status = GetLastError();
  132. -                goto out_free;
  133. -            }
  134. -
  135. -            if (last_entry) /* fix last_entry pointer */
  136. -                last_entry = (nfs41_readdir_entry*)(tmp + diff);
  137. -            buffer = tmp;
  138. -            buffer_len *= 2;
  139. -            len = buffer_len - total_len;
  140. -        }
  141. -
  142. -        /* fetch the next group of entries */
  143. -        status = nfs41_readdir(session, eadir, &attr_request,
  144. -            &cookie, buffer + total_len, &len, &eof);
  145. -        if (status)
  146. -            goto out_free;
  147. -
  148. -        if (last_entry == NULL) {
  149. -            /* initialize last_entry to the front of the list */
  150. -            last_entry = (nfs41_readdir_entry*)(buffer + total_len);
  151. -        } else if (len) {
  152. -            /* link the previous list to the new one */
  153. -            last_entry->next_entry_offset = (uint32_t)FIELD_OFFSET(
  154. -                nfs41_readdir_entry, name) + last_entry->name_len;
  155. -        }
  156. -
  157. -        /* find the new last entry */
  158. -        while (last_entry->next_entry_offset) {
  159. -            last_entry = (nfs41_readdir_entry*)((char*)last_entry +
  160. -                last_entry->next_entry_offset);
  161. -        }
  162. -
  163. -        cookie.cookie = last_entry->cookie;
  164. -        total_len += len;
  165. -    }
  166. -
  167. -    *buffer_out = buffer;
  168. -    *length_out = total_len;
  169. -out:
  170. -    return status;
  171. -
  172. -out_free:
  173. -    free(buffer);
  174. -    goto out;
  175. -}
  176. -
  177.  #define ALIGNED_EASIZE(len) \
  178.      (align4(sizeof(FILE_GET_EA_INFORMATION) + (len)))
  179.  
  180. @@ -481,6 +396,9 @@ static int get_ea_list(
  181.      PFILE_GET_EA_INFORMATION ea_list;
  182.      uint32_t entry_len, ea_size;
  183.      int status = NO_ERROR;
  184. +    bitmap4 attr_request = {
  185. +        .count = 0 /* don't request attributes */
  186. +    };
  187.  
  188.      EnterCriticalSection(&state->ea.lock);
  189.  
  190. @@ -492,7 +410,8 @@ static int get_ea_list(
  191.      }
  192.  
  193.      /* read the entire directory into a nfs41_readdir_entry buffer */
  194. -    status = read_entire_dir(state->session, eadir, &entry_list, &entry_len);
  195. +    status = read_entire_dir(state->session, eadir, &attr_request,
  196. +        &entry_list, &entry_len);
  197.      if (status)
  198.          goto out;
  199.  
  200. @@ -512,7 +431,7 @@ static int get_ea_list(
  201.      *ealist_out = state->ea.list = ea_list;
  202.      *eaindex_out = state->ea.index;
  203.  out_free:
  204. -    free(entry_list); /* allocated by read_entire_dir() */
  205. +    free_entire_dir(entry_list); /* allocated by read_entire_dir() */
  206.  out:
  207.      LeaveCriticalSection(&state->ea.lock);
  208.      return status;
  209. diff --git a/daemon/util.c b/daemon/util.c
  210. index 8d7f950..7029bb6 100644
  211. --- a/daemon/util.c
  212. +++ b/daemon/util.c
  213. @@ -1,6 +1,6 @@
  214.  /* NFSv4.1 client for Windows
  215.   * Copyright (C) 2012 The Regents of the University of Michigan
  216. - * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  217. + * Copyright (C) 2023-2026 Roland Mainz <roland.mainz@nrubsig.org>
  218.   *
  219.   * Olga Kornievskaia <aglo@umich.edu>
  220.   * Casey Bodley <cbodley@umich.edu>
  221. @@ -922,3 +922,93 @@ create_symlink_chgrp_out:
  222.      return chgrp_status;
  223.  }
  224.  #endif /* NFS41_DRIVER_SETGID_NEWGRP_SUPPORT */
  225. +
  226. +
  227. +#define READDIR_LEN_INITIAL 8192
  228. +#define READDIR_LEN_MIN 2048
  229. +
  230. +/* call readdir repeatedly to get a complete list of entries */
  231. +int read_entire_dir(
  232. +    IN nfs41_session *session,
  233. +    IN nfs41_path_fh *dir,
  234. +    IN bitmap4 *attr_request,
  235. +    OUT unsigned char **restrict buffer_out,
  236. +    OUT uint32_t *restrict length_out)
  237. +{
  238. +    nfs41_readdir_cookie cookie = { 0 };
  239. +    nfs41_readdir_entry *last_entry;
  240. +    unsigned char *buffer;
  241. +    uint32_t buffer_len, len, total_len;
  242. +    bool_t eof;
  243. +    int status = NO_ERROR;
  244. +
  245. +    /* Allocate the buffer for readdir entries */
  246. +    buffer_len = READDIR_LEN_INITIAL;
  247. +    buffer = calloc(1, buffer_len);
  248. +    if (buffer == NULL) {
  249. +        status = GetLastError();
  250. +        goto out;
  251. +    }
  252. +
  253. +    last_entry = NULL;
  254. +    total_len = 0;
  255. +    eof = FALSE;
  256. +
  257. +    while (!eof) {
  258. +        len = buffer_len - total_len;
  259. +        if (len < READDIR_LEN_MIN) {
  260. +            const ptrdiff_t diff = (unsigned char*)last_entry - buffer;
  261. +            /* Reallocate the buffer to fit more entries */
  262. +            unsigned char *tmp = realloc(buffer, (size_t)buffer_len * 2L);
  263. +            if (tmp == NULL) {
  264. +                status = GetLastError();
  265. +                goto out_free;
  266. +            }
  267. +
  268. +            if (last_entry) /* Fix last_entry pointer */
  269. +                last_entry = (nfs41_readdir_entry *)(tmp + diff);
  270. +            buffer = tmp;
  271. +            buffer_len *= 2;
  272. +            len = buffer_len - total_len;
  273. +        }
  274. +
  275. +        /* Fetch the next group of entries */
  276. +        status = nfs41_readdir(session, dir, attr_request,
  277. +            &cookie, buffer + total_len, &len, &eof);
  278. +        if (status)
  279. +            goto out_free;
  280. +
  281. +        if (last_entry == NULL) {
  282. +            /* Initialize last_entry to the front of the list */
  283. +            last_entry = (nfs41_readdir_entry *)(buffer + total_len);
  284. +        } else if (len) {
  285. +            /* Link the previous list to the new one */
  286. +            last_entry->next_entry_offset = (uint32_t)FIELD_OFFSET(
  287. +                nfs41_readdir_entry, name) + last_entry->name_len;
  288. +        }
  289. +
  290. +        /* Find the new last entry */
  291. +        while (last_entry->next_entry_offset) {
  292. +            last_entry = (nfs41_readdir_entry*)((char*)last_entry +
  293. +                last_entry->next_entry_offset);
  294. +        }
  295. +
  296. +        cookie.cookie = last_entry->cookie;
  297. +        total_len += len;
  298. +    }
  299. +
  300. +    *buffer_out = buffer;
  301. +    *length_out = total_len;
  302. +out:
  303. +    return status;
  304. +
  305. +out_free:
  306. +    free_entire_dir(buffer);
  307. +    goto out;
  308. +}
  309. +
  310. +void free_entire_dir(
  311. +    unsigned char *restrict buffer)
  312. +{
  313. +    free(buffer);
  314. +}
  315. diff --git a/daemon/util.h b/daemon/util.h
  316. index dc0ea07..362df4c 100644
  317. --- a/daemon/util.h
  318. +++ b/daemon/util.h
  319. @@ -1,6 +1,6 @@
  320.  /* NFSv4.1 client for Windows
  321.   * Copyright (C) 2012 The Regents of the University of Michigan
  322. - * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  323. + * Copyright (C) 2023-2026 Roland Mainz <roland.mainz@nrubsig.org>
  324.   *
  325.   * Olga Kornievskaia <aglo@umich.edu>
  326.   * Casey Bodley <cbodley@umich.edu>
  327. @@ -458,4 +458,16 @@ int chgrp_to_primarygroup(
  328.      IN nfs41_open_state *state);
  329.  #endif /* NFS41_DRIVER_SETGID_NEWGRP_SUPPORT */
  330.  
  331. +typedef struct __bitmap4 bitmap4;
  332. +typedef struct __nfs41_path_fh nfs41_path_fh;
  333. +typedef struct __nfs41_session nfs41_session;
  334. +
  335. +int read_entire_dir(
  336. +    IN nfs41_session *session,
  337. +    IN nfs41_path_fh *dir,
  338. +    IN bitmap4 *attr_request,
  339. +    OUT unsigned char **restrict buffer_out,
  340. +    OUT uint32_t *restrict length_out);
  341. +void free_entire_dir(
  342. +    unsigned char *restrict buffer);
  343.  #endif /* !__NFS41_DAEMON_UTIL_H__ */
  344. diff --git a/daemon/winstreams.c b/daemon/winstreams.c
  345. index 0770131..1478fbe 100644
  346. --- a/daemon/winstreams.c
  347. +++ b/daemon/winstreams.c
  348. @@ -206,100 +206,6 @@ int parse_win32stream_name(
  349.      return NO_ERROR;
  350.  }
  351.  
  352. -#define READDIR_LEN_INITIAL 8192
  353. -#define READDIR_LEN_MIN 2048
  354. -
  355. -/* call readdir repeatedly to get a complete list of entries */
  356. -static
  357. -int read_entire_dir(
  358. -    IN nfs41_session *session,
  359. -    IN nfs41_path_fh *dir,
  360. -    OUT unsigned char **restrict buffer_out,
  361. -    OUT uint32_t *restrict length_out)
  362. -{
  363. -    nfs41_readdir_cookie cookie = { 0 };
  364. -    nfs41_readdir_entry *last_entry;
  365. -    unsigned char *buffer;
  366. -    uint32_t buffer_len, len, total_len;
  367. -    bool_t eof;
  368. -    int status = NO_ERROR;
  369. -    /* Attributes for stream */
  370. -    bitmap4 attr_request = {
  371. -        .count = 2,
  372. -        .arr = {
  373. -            [0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
  374. -                FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID |
  375. -                FATTR4_WORD0_FILEID,
  376. -            [1] = FATTR4_WORD1_SPACE_USED,
  377. -            [2] = 0
  378. -        }
  379. -    };
  380. -
  381. -    /* allocate the buffer for readdir entries */
  382. -    buffer_len = READDIR_LEN_INITIAL;
  383. -    buffer = calloc(1, buffer_len);
  384. -    if (buffer == NULL) {
  385. -        status = GetLastError();
  386. -        goto out;
  387. -    }
  388. -
  389. -    last_entry = NULL;
  390. -    total_len = 0;
  391. -    eof = FALSE;
  392. -
  393. -    while (!eof) {
  394. -        len = buffer_len - total_len;
  395. -        if (len < READDIR_LEN_MIN) {
  396. -            const ptrdiff_t diff = (unsigned char*)last_entry - buffer;
  397. -            /* realloc the buffer to fit more entries */
  398. -            unsigned char *tmp = realloc(buffer, (size_t)buffer_len * 2L);
  399. -            if (tmp == NULL) {
  400. -                status = GetLastError();
  401. -                goto out_free;
  402. -            }
  403. -
  404. -            if (last_entry) /* Fix last_entry pointer */
  405. -                last_entry = (nfs41_readdir_entry *)(tmp + diff);
  406. -            buffer = tmp;
  407. -            buffer_len *= 2;
  408. -            len = buffer_len - total_len;
  409. -        }
  410. -
  411. -        /* Fetch the next group of entries */
  412. -        status = nfs41_readdir(session, dir, &attr_request,
  413. -            &cookie, buffer + total_len, &len, &eof);
  414. -        if (status)
  415. -            goto out_free;
  416. -
  417. -        if (last_entry == NULL) {
  418. -            /* Initialize last_entry to the front of the list */
  419. -            last_entry = (nfs41_readdir_entry *)(buffer + total_len);
  420. -        } else if (len) {
  421. -            /* Link the previous list to the new one */
  422. -            last_entry->next_entry_offset = (uint32_t)FIELD_OFFSET(
  423. -                nfs41_readdir_entry, name) + last_entry->name_len;
  424. -        }
  425. -
  426. -        /* Find the new last entry */
  427. -        while (last_entry->next_entry_offset) {
  428. -            last_entry = (nfs41_readdir_entry*)((char*)last_entry +
  429. -                last_entry->next_entry_offset);
  430. -        }
  431. -
  432. -        cookie.cookie = last_entry->cookie;
  433. -        total_len += len;
  434. -    }
  435. -
  436. -    *buffer_out = buffer;
  437. -    *length_out = total_len;
  438. -out:
  439. -    return status;
  440. -
  441. -out_free:
  442. -    free(buffer);
  443. -    goto out;
  444. -}
  445. -
  446.  #define ALIGNED_STREAMINFOSIZE(namebytelen) \
  447.      (align8(sizeof(FILE_STREAM_INFORMATION) + (namebytelen)))
  448.  
  449. @@ -488,9 +394,21 @@ int get_stream_list(
  450.      PFILE_STREAM_INFORMATION stream_list;
  451.      uint32_t entry_len, stream_list_size;
  452.      int status = NO_ERROR;
  453. +    /* Attributes for stream */
  454. +    bitmap4 attr_request = {
  455. +        .count = 2,
  456. +        .arr = {
  457. +            [0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
  458. +                FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID |
  459. +                FATTR4_WORD0_FILEID,
  460. +            [1] = FATTR4_WORD1_SPACE_USED,
  461. +            [2] = 0
  462. +        }
  463. +    };
  464.  
  465.      /* read the entire directory into a |nfs41_readdir_entry| buffer */
  466.      status = read_entire_dir(state->session, streamfile,
  467. +        &attr_request,
  468.          &entry_list, &entry_len);
  469.      if (status)
  470.          goto out;
  471. @@ -517,7 +435,7 @@ int get_stream_list(
  472.      *streamlist_out = stream_list;
  473.      *streamlist_out_size = stream_list_size;
  474.  out_free:
  475. -    free(entry_list); /* allocated by |read_entire_dir()| */
  476. +    free_entire_dir(entry_list); /* allocated by |read_entire_dir()| */
  477.  out:
  478.      return status;
  479.  }
  480. --
  481. 2.51.0
  482.  
  483. From 1eb19df3bca78c808536a81611e3c54ba4afd8dc Mon Sep 17 00:00:00 2001
  484. From: Roland Mainz <roland.mainz@nrubsig.org>
  485. Date: Tue, 6 Jan 2026 12:10:00 +0100
  486. Subject: [PATCH 3/6] daemon: Clarify comment that we use NFS named attributes
  487.  for Windows EA, not RFC8726 XATTRs
  488.  
  489. Clarify comment that we use NFSv4 named attributes for Windows EA
  490. and not the RFC8726 XATTRs extension.
  491.  
  492. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  493. ---
  494. daemon/ea.c | 6 +++---
  495.  1 file changed, 3 insertions(+), 3 deletions(-)
  496.  
  497. diff --git a/daemon/ea.c b/daemon/ea.c
  498. index b9c94c1..edae48e 100644
  499. --- a/daemon/ea.c
  500. +++ b/daemon/ea.c
  501. @@ -41,11 +41,11 @@
  502.  #endif
  503.  
  504.  /*
  505. - * |WIN_NFS4_EA_NAME_PREFIX| - Prefix for Windows EA in NFSv4
  506. - * XATTR (extended attributes) namespace
  507. + * |WIN_NFS4_EA_NAME_PREFIX| - Prefix for Windows EAs in NFSv4
  508. + * named attribute namespace
  509.   *
  510.   * We need such a prefix to avoid colliding with other users
  511. - * in the NFSv4 XATTR namespace - for example SUN Microsystrems
  512. + * in the NFSv4 named attribute namespace - for example SUN Microsystrems
  513.   * (Solaris, Illumos, ...) uses "SUNWattr_" as prefix, and setting
  514.   * such attributes can cause data corruption (or in case of
  515.   * "SUNWattr_ro" will fail, because the attribute file is
  516. --
  517. 2.51.0
  518.  
  519. From 01a08d5d037bd496291fa1b532ae3f1c202bcee5 Mon Sep 17 00:00:00 2001
  520. From: Roland Mainz <roland.mainz@nrubsig.org>
  521. Date: Tue, 6 Jan 2026 12:24:36 +0100
  522. Subject: [PATCH 4/6] daemon: Rename |nfs41_superblock.ea_support| to
  523.  |nfs41_superblock.nfs_namedattr_support|
  524.  
  525. Rename |nfs41_superblock.ea_support| to |nfs41_superblock.nfs_namedattr_support|.
  526.  
  527. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  528. ---
  529. daemon/acl.c              |  6 +++---
  530.  daemon/aclutil.c          | 28 ++++++++++++++--------------
  531.  daemon/nfs41.h            |  4 ++--
  532.  daemon/nfs41_superblock.c |  8 ++++----
  533.  daemon/winstreams.c       |  2 +-
  534.  5 files changed, 24 insertions(+), 24 deletions(-)
  535.  
  536. diff --git a/daemon/acl.c b/daemon/acl.c
  537. index 2d7546b..4dfcb8a 100644
  538. --- a/daemon/acl.c
  539. +++ b/daemon/acl.c
  540. @@ -1,6 +1,6 @@
  541.  /* NFSv4.1 client for Windows
  542.   * Copyright (C) 2012 The Regents of the University of Michigan
  543. - * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  544. + * Copyright (C) 2023-2026 Roland Mainz <roland.mainz@nrubsig.org>
  545.   *
  546.   * Olga Kornievskaia <aglo@umich.edu>
  547.   * Casey Bodley <cbodley@umich.edu>
  548. @@ -168,7 +168,7 @@ static int handle_getacl(void *daemon_context, nfs41_upcall *upcall)
  549.          DPRINTF(ACLLVL2, ("handle_getacl: DACL_SECURITY_INFORMATION\n"));
  550.          status = convert_nfs4acl_2_dacl(nfs41dg,
  551.              info.acl, state->type, &dacl, &sids,
  552. -            state->file.fh.superblock->ea_support?true:false);
  553. +            state->file.fh.superblock->nfs_namedattr_support?true:false);
  554.          if (status)
  555.              goto out;
  556.          status = SetSecurityDescriptorDacl(&sec_desc, TRUE, dacl, TRUE);
  557. @@ -369,7 +369,7 @@ static int handle_setacl(void *daemon_context, nfs41_upcall *upcall)
  558.          }
  559.          status = map_dacl_2_nfs4acl(acl, sid, gsid, &nfs4_acl,
  560.               state->type,
  561. -             state->file.fh.superblock->ea_support?true:false,
  562. +             state->file.fh.superblock->nfs_namedattr_support?true:false,
  563.              nfs41dg->localdomain_name);
  564.          if (status)
  565.              goto out;
  566. diff --git a/daemon/aclutil.c b/daemon/aclutil.c
  567. index 6724543..1163a02 100644
  568. --- a/daemon/aclutil.c
  569. +++ b/daemon/aclutil.c
  570. @@ -43,9 +43,9 @@
  571.  static void map_winace2nfs4aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags);
  572.  static void map_nfs4aceflags2winaceflags(uint32_t nfs4_aceflags, DWORD *win_aceflags);
  573.  static void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
  574. -    int file_type, bool named_attr_support, uint32_t *nfs4_mask);
  575. +    int file_type, bool nfs_namedattr_support, uint32_t *nfs4_mask);
  576.  static void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
  577. -    int file_type, bool named_attr_support, ACCESS_MASK *win_mask);
  578. +    int file_type, bool nfs_namedattr_support, ACCESS_MASK *win_mask);
  579.  
  580.   void convert_nfs4name_2_user_domain(LPSTR nfs4name,
  581.      LPSTR *domain)
  582. @@ -116,7 +116,7 @@ static int check_4_special_identifiers(const char *restrict who,
  583.  
  584.  int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
  585.      nfsacl41 *acl, int file_type, PACL *dacl_out, PSID **sids_out,
  586. -    bool named_attr_support)
  587. +    bool nfs_namedattr_support)
  588.  {
  589.      int status = ERROR_NOT_SUPPORTED, size = 0;
  590.      uint32_t nfs_i = 0, win_i = 0;
  591. @@ -127,9 +127,9 @@ int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
  592.      BOOLEAN flag;
  593.  
  594.      DPRINTF(ACLLVL2, ("--> convert_nfs4acl_2_dacl(acl=0x%p,"
  595. -        "file_type='%s'(=%d), named_attr_support=%d)\n",
  596. +        "file_type='%s'(=%d), nfs_namedattr_support=%d)\n",
  597.          acl, map_nfs_ftype2str(file_type), file_type,
  598. -        (int)named_attr_support));
  599. +        (int)nfs_namedattr_support));
  600.  
  601.      bool *skip_aces = _alloca(acl->count * sizeof(bool));
  602.  
  603. @@ -231,7 +231,7 @@ int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
  604.              map_nfs4aceflags2winaceflags(curr_nfsace->aceflag,
  605.                  &win_aceflags);
  606.              map_nfs4acemask2winaccessmask(curr_nfsace->acemask,
  607. -                file_type, named_attr_support, &mask);
  608. +                file_type, nfs_namedattr_support, &mask);
  609.  
  610.              if (DPRINTF_LEVEL_ENABLED(ACLLVL1)) {
  611.                  dprintf_out("nfs2win: acl->aces[%d].who='%s': "
  612. @@ -444,7 +444,7 @@ static void map_nfs4aceflags2winaceflags(uint32_t nfs4_aceflags, DWORD *win_acef
  613.  
  614.  static
  615.  void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
  616. -    int file_type, bool named_attr_support, uint32_t *nfs4_mask)
  617. +    int file_type, bool nfs_namedattr_support, uint32_t *nfs4_mask)
  618.  {
  619.      *nfs4_mask = 0;
  620.  
  621. @@ -458,7 +458,7 @@ void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
  622.          uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
  623.  
  624.  #ifdef MAP_WIN32GENERIC2ACE4GENERIC
  625. -        if (!named_attr_support) {
  626. +        if (!nfs_namedattr_support) {
  627.              /*
  628.               * Filter out unsupported features for
  629.               * |GENERIC_*| --> |ACE_*ATTR| conversion.
  630. @@ -568,7 +568,7 @@ void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
  631.  
  632.  static
  633.  void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
  634. -    int file_type, bool named_attr_support, ACCESS_MASK *win_mask)
  635. +    int file_type, bool nfs_namedattr_support, ACCESS_MASK *win_mask)
  636.  {
  637.      *win_mask = 0;
  638.  
  639. @@ -582,7 +582,7 @@ void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
  640.      uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
  641.      uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
  642.  
  643. -    if (!named_attr_support) {
  644. +    if (!nfs_namedattr_support) {
  645.          /*
  646.           * Filter out unsupported features for
  647.           * |ACE_*ATTR| --> |GENERIC_*| conversion.
  648. @@ -974,7 +974,7 @@ out:
  649.  }
  650.  
  651.  int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
  652. -    int file_type, bool named_attr_support, char *domain)
  653. +    int file_type, bool nfs_namedattr_support, char *domain)
  654.  {
  655.      int status;
  656.      if (acl == NULL) {
  657. @@ -993,7 +993,7 @@ int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
  658.              uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
  659.  #ifdef MAP_WIN32GENERIC2ACE4GENERIC
  660.              /* Filter out unsupported features */
  661. -            if (!named_attr_support) {
  662. +            if (!nfs_namedattr_support) {
  663.                  ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
  664.              }
  665.  #endif /* MAP_WIN32GENERIC2ACE4GENERIC */
  666. @@ -1003,7 +1003,7 @@ int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
  667.              uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
  668.  #ifdef MAP_WIN32GENERIC2ACE4GENERIC
  669.              /* Filter out unsupported features */
  670. -            if (!named_attr_support) {
  671. +            if (!nfs_namedattr_support) {
  672.                  ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
  673.              }
  674.  #endif /* MAP_WIN32GENERIC2ACE4GENERIC */
  675. @@ -1099,7 +1099,7 @@ int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
  676.              map_winace2nfs4aceflags(ace->AceFlags,
  677.                  &curr_nfsace->aceflag);
  678.              map_winaccessmask2nfs4acemask(win_mask,
  679. -                file_type, named_attr_support,
  680. +                file_type, nfs_namedattr_support,
  681.                  &curr_nfsace->acemask);
  682.  
  683.              /*
  684. diff --git a/daemon/nfs41.h b/daemon/nfs41.h
  685. index e016d77..953750f 100644
  686. --- a/daemon/nfs41.h
  687. +++ b/daemon/nfs41.h
  688. @@ -1,6 +1,6 @@
  689.  /* NFSv4.1 client for Windows
  690.   * Copyright (C) 2012 The Regents of the University of Michigan
  691. - * Copyright (C) 2024-2025 Roland Mainz <roland.mainz@nrubsig.org>
  692. + * Copyright (C) 2024-2026 Roland Mainz <roland.mainz@nrubsig.org>
  693.   *
  694.   * Olga Kornievskaia <aglo@umich.edu>
  695.   * Casey Bodley <cbodley@umich.edu>
  696. @@ -57,7 +57,7 @@ typedef struct __nfs41_superblock {
  697.      unsigned int cansettime : 1;
  698.      unsigned int link_support : 1;
  699.      unsigned int symlink_support : 1;
  700. -    unsigned int ea_support : 1;
  701. +    unsigned int nfs_namedattr_support : 1;
  702.      unsigned int case_preserving : 1;
  703.      unsigned int case_insensitive : 1;
  704.      unsigned int sparse_file_support : 1;
  705. diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
  706. index 1a767d3..4095ca0 100644
  707. --- a/daemon/nfs41_superblock.c
  708. +++ b/daemon/nfs41_superblock.c
  709. @@ -125,7 +125,7 @@ static int get_superblock_attrs(
  710.      superblock->aclsupport = info.aclsupport;
  711.      superblock->link_support = info.link_support;
  712.      superblock->symlink_support = info.symlink_support;
  713. -    superblock->ea_support = supports_named_attrs;
  714. +    superblock->nfs_namedattr_support = supports_named_attrs;
  715.  
  716.  #ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
  717.      if (root->force_case_preserving == TRISTATE_BOOL_NOT_SET) {
  718. @@ -303,7 +303,7 @@ void nfs41_superblock_fs_attributes(
  719.          FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_HARD_LINKS;
  720.      if (superblock->symlink_support)
  721.          FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_REPARSE_POINTS;
  722. -    if (superblock->ea_support) {
  723. +    if (superblock->nfs_namedattr_support) {
  724.          FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_EXTENDED_ATTRIBUTES;
  725.  #ifdef NFS41_WINSTREAMS_SUPPORT
  726.          FsAttrs->FileSystemAttributes |= FILE_NAMED_STREAMS;
  727. @@ -335,7 +335,7 @@ void nfs41_superblock_fs_attributes(
  728.      DPRINTF(SBLVL, ("FileFsAttributeInformation: "
  729.          "link_support=%u, "
  730.          "symlink_support=%u, "
  731. -        "ea_support=%u, "
  732. +        "nfs_namedattr_support=%u, "
  733.          "case_preserving=%u, "
  734.          "case_insensitive=%u, "
  735.          "aclsupport=%u, "
  736. @@ -343,7 +343,7 @@ void nfs41_superblock_fs_attributes(
  737.          "FileSystemAttributes=0x%lx\n",
  738.          superblock->link_support,
  739.          superblock->symlink_support,
  740. -        superblock->ea_support,
  741. +        superblock->nfs_namedattr_support,
  742.          (int)superblock->case_preserving,
  743.          (int)superblock->case_insensitive,
  744.          superblock->aclsupport,
  745. diff --git a/daemon/winstreams.c b/daemon/winstreams.c
  746. index 1478fbe..929fb81 100644
  747. --- a/daemon/winstreams.c
  748. +++ b/daemon/winstreams.c
  749. @@ -449,7 +449,7 @@ int get_streaminformation(
  750.      int status;
  751.      nfs41_path_fh parent = { 0 };
  752.  
  753. -    if (!state->file.fh.superblock->ea_support) {
  754. +    if (!state->file.fh.superblock->nfs_namedattr_support) {
  755.          return ERROR_NOT_SUPPORTED;
  756.      }
  757.  
  758. --
  759. 2.51.0
  760.  
  761. From 5f50588ec8fd04b7d7c46f027f02490ab3c21391 Mon Sep 17 00:00:00 2001
  762. From: Roland Mainz <roland.mainz@nrubsig.org>
  763. Date: Tue, 6 Jan 2026 12:37:02 +0100
  764. Subject: [PATCH 5/6] README.md,docs: Document Windows names streams support
  765.  
  766. Document Windows names streams support.
  767.  
  768. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  769. ---
  770. README.md       |  8 ++++++++
  771.  docs/README.xml | 12 ++++++++++++
  772.  2 files changed, 20 insertions(+)
  773.  
  774. diff --git a/README.md b/README.md
  775. index 2bbb83d..df37c7b 100644
  776. --- a/README.md
  777. +++ b/README.md
  778. @@ -139,6 +139,14 @@ NFSv4.2/NFSv4.1 filesystem driver for Windows 10/11 & Windows Server
  779.      sparse files. Requires on Win11 \>= 22H2 because it relies on
  780.      `|CopyFile2()|` flag `|COPY_FILE_ENABLE_SPARSE_COPY|`.
  781.  
  782. +- Windows "named streams"/[Alternate Data
  783. +  Stream](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c54dec26-1551-4d3a-a0ea-4fa40f848eb3)
  784. +  support
  785. +
  786. +  - Supports Win32 APIs `|FileStreamInformation|`
  787. +
  788. +  - Requires NFSv4.1 server which supports the NFSv4.1 named attributes.
  789. +
  790.  - Case-insensitive filesystem support
  791.  
  792.    - Requires NFSv4.1 server which supports the
  793. diff --git a/docs/README.xml b/docs/README.xml
  794. index e7f3a6c..39e1fdf 100644
  795. --- a/docs/README.xml
  796. +++ b/docs/README.xml
  797. @@ -141,6 +141,18 @@
  798.            </itemizedlist>
  799.          </para>
  800.        </listitem>
  801. +      <listitem>
  802. +        <para>Windows "named streams"/<link xl:href="https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c54dec26-1551-4d3a-a0ea-4fa40f848eb3">Alternate Data Stream</link> support
  803. +          <itemizedlist>
  804. +            <listitem>
  805. +              <para>Supports Win32 APIs <literal>|<link xl:href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_stream_information">FileStreamInformation</link>|</literal></para>
  806. +            </listitem>
  807. +            <listitem>
  808. +              <para>Requires NFSv4.1 server which supports the NFSv4.1 named attributes.</para>
  809. +            </listitem>
  810. +          </itemizedlist>
  811. +        </para>
  812. +      </listitem>
  813.        <listitem>
  814.          <para>Case-insensitive filesystem support
  815.            <itemizedlist>
  816. --
  817. 2.51.0
  818.  
  819. From 83cbc2adb01d0003991859ed039827f17a15adcf Mon Sep 17 00:00:00 2001
  820. From: Dan Shelton <dan.f.shelton@gmail.com>
  821. Date: Tue, 6 Jan 2026 13:41:14 +0100
  822. Subject: [PATCH 6/6] daemon: Fix printf()-style&co format argument warning
  823.  
  824. Fix printf()-style&co format argument warning.
  825.  
  826. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  827. ---
  828. daemon/acl.c | 2 +-
  829.  1 file changed, 1 insertion(+), 1 deletion(-)
  830.  
  831. diff --git a/daemon/acl.c b/daemon/acl.c
  832. index 4dfcb8a..0b97538 100644
  833. --- a/daemon/acl.c
  834. +++ b/daemon/acl.c
  835. @@ -51,7 +51,7 @@ static int parse_getacl(
  836.  
  837.      EASSERT(length == 0);
  838.  
  839. -    DPRINTF(1, ("parsing NFS41_SYSOP_ACL_QUERY: secinfo=0xlx\n",
  840. +    DPRINTF(1, ("parsing NFS41_SYSOP_ACL_QUERY: secinfo=0x%lx\n",
  841.          (long)args->query_secinfo));
  842.  out:
  843.      return status;
  844. --
  845. 2.51.0

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