pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patches for mklink fixes, symlink translation fixes+misc, 2025-02-06
Posted by Anonymous on Thu 6th Feb 2025 14:00
raw | new post

  1. From 9359eb1f3b2fb1173bd78096cb5df3299de8ba70 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Thu, 6 Feb 2025 12:38:50 +0100
  4. Subject: [PATCH 1/3] daemon: Split symlink handlers into symlink get/set
  5.  variations
  6.  
  7. Cleanup: Split symlink handlers into symlink get/set variations
  8.  
  9. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  10. ---
  11. daemon/symlink.c | 216 +++++++++++++++++++++++++++--------------------
  12.  1 file changed, 125 insertions(+), 91 deletions(-)
  13.  
  14. diff --git a/daemon/symlink.c b/daemon/symlink.c
  15. index b601f01..4eeece3 100644
  16. --- a/daemon/symlink.c
  17. +++ b/daemon/symlink.c
  18. @@ -69,7 +69,7 @@ static int abs_path_link(
  19.          }
  20.  
  21.          /* copy the component and add a \ */
  22. -        if (FAILED(StringCchCopyNA(path_pos, path_max-path_pos, name.name,
  23. +        if (FAILED(StringCchCopyNA(path_pos, path_max-path_pos, name.name,
  24.                  name.len))) {
  25.              status = ERROR_BUFFER_OVERFLOW;
  26.              goto out;
  27. @@ -189,116 +189,61 @@ out:
  28.  }
  29.  
  30.  
  31. -/* NFS41_SYSOP_SYMLINK_GET, NFS41_SYSOP_SYMLINK_SET */
  32. -static int parse_symlink(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
  33. +/* NFS41_SYSOP_SYMLINK_GET */
  34. +static int parse_symlink_get(unsigned char *buffer, uint32_t length,
  35. +    nfs41_upcall *upcall)
  36.  {
  37.      symlink_upcall_args *args = &upcall->args.symlink;
  38.      int status;
  39.  
  40.      status = get_name(&buffer, &length, &args->path);
  41. -    if (status) goto out;
  42. -
  43. -    if (upcall->opcode == NFS41_SYSOP_SYMLINK_SET) {
  44. -        /*
  45. -         * args->target_set is not const because handle_symlink() might
  46. -         * have to replace '\\' with '/'
  47. -         */
  48. -        status = get_name(&buffer, &length,
  49. -            (const char **)(&args->target_set));
  50. -
  51. -        DPRINTF(1,
  52. -            ("parsing NFS41_SYSOP_SYMLINK_SET: "
  53. -            "path='%s' target='%s'\n",
  54. -            args->path, args->target_set));
  55. -    }
  56. -    else if (upcall->opcode == NFS41_SYSOP_SYMLINK_GET) {
  57. -        args->target_set = NULL;
  58. +    if (status)
  59. +        goto out;
  60.  
  61. -        DPRINTF(1,
  62. -            ("parsing NFS41_SYSOP_SYMLINK_GET: "
  63. -            "path='%s' target='%s'\n",
  64. -            args->path, args->target_set));
  65. -    }
  66. -    else {
  67. -        status = ERROR_INVALID_PARAMETER;
  68. -        eprintf("parse_symlink: Unknown upcall->opcode=%d\n",
  69. -            (int)upcall->opcode);
  70. -    }
  71. +    args->target_set = NULL;
  72. +
  73. +    DPRINTF(1,
  74. +        ("parse_symlink_get: parsing NFS41_SYSOP_SYMLINK_GET: "
  75. +        "path='%s' target='%s'\n",
  76. +        args->path, args->target_set));
  77.  
  78.  out:
  79.      return status;
  80.  }
  81.  
  82. -static int handle_symlink(void *daemon_context, nfs41_upcall *upcall)
  83. +static int handle_symlink_get(void *daemon_context, nfs41_upcall *upcall)
  84.  {
  85.      symlink_upcall_args *args = &upcall->args.symlink;
  86.      nfs41_open_state *state = upcall->state_ref;
  87.      int status = NO_ERROR;
  88.  
  89. -    if (upcall->opcode == NFS41_SYSOP_SYMLINK_SET) {
  90. -        nfs41_file_info info, createattrs;
  91. -
  92. -        /* don't send windows slashes to the server */
  93. -        char *p;
  94. -        for (p = args->target_set; *p; p++) if (*p == '\\') *p = '/';
  95. -
  96. -        if (state->file.fh.len) {
  97. -            /* the check in handle_open() didn't catch that we're creating
  98. -             * a symlink, so we have to remove the file it already created */
  99. -            eprintf("handle_symlink: attempting to create a symlink when "
  100. -                "the file=%s was already created on open; sending REMOVE "
  101. -                "first\n", state->file.path->path);
  102. -            status = nfs41_remove(state->session, &state->parent,
  103. -                &state->file.name, state->file.fh.fileid);
  104. -            if (status) {
  105. -                eprintf("nfs41_remove() for symlink='%s' failed with '%s'\n",
  106. -                    args->target_set, nfs_error_string(status));
  107. -                status = map_symlink_errors(status);
  108. -                goto out;
  109. -            }
  110. -        }
  111. +    uint32_t len;
  112.  
  113. -        /* create the symlink */
  114. -        createattrs.attrmask.count = 2;
  115. -        createattrs.attrmask.arr[0] = 0;
  116. -        createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE;
  117. -        createattrs.mode = 0777;
  118. -        status = nfs41_create(state->session, NF4LNK, &createattrs,
  119. -            args->target_set, &state->parent, &state->file, &info);
  120. -        if (status) {
  121. -            eprintf("nfs41_create() for symlink='%s' failed with '%s'\n",
  122. -                args->target_set, nfs_error_string(status));
  123. -            status = map_symlink_errors(status);
  124. -            goto out;
  125. -        }
  126. -    } else {
  127. -        uint32_t len;
  128. -
  129. -        /* read the link */
  130. -        status = nfs41_readlink(state->session, &state->file,
  131. -            NFS41_MAX_PATH_LEN, args->target_get.path, &len);
  132. -        if (status) {
  133. -            eprintf("nfs41_readlink() for filename='%s' failed with '%s'\n",
  134. -                state->file.path->path, nfs_error_string(status));
  135. -            status = map_symlink_errors(status);
  136. -            goto out;
  137. -        }
  138. -        args->target_get.len = (unsigned short)len;
  139. -        DPRINTF(2, ("returning symlink target '%s'\n", args->target_get.path));
  140. +    /* read the link */
  141. +    status = nfs41_readlink(state->session, &state->file,
  142. +        NFS41_MAX_PATH_LEN, args->target_get.path, &len);
  143. +    if (status) {
  144. +        eprintf("handle_symlink_get: "
  145. +            "nfs41_readlink() for filename='%s' failed with '%s'\n",
  146. +            state->file.path->path, nfs_error_string(status));
  147. +        status = map_symlink_errors(status);
  148. +        goto out;
  149.      }
  150. +    args->target_get.len = (unsigned short)len;
  151. +    DPRINTF(2,
  152. +        ("returning symlink target '%s'\n", args->target_get.path));
  153. +
  154.  out:
  155.      return status;
  156.  }
  157.  
  158. -static int marshall_symlink(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
  159. +static int marshall_symlink_get(unsigned char *buffer, uint32_t *length,
  160. +    nfs41_upcall *upcall)
  161.  {
  162.      symlink_upcall_args *args = &upcall->args.symlink;
  163.      unsigned short len = (args->target_get.len + 1) * sizeof(WCHAR);
  164.      int status = NO_ERROR;
  165.  
  166. -    if (upcall->opcode == NFS41_SYSOP_SYMLINK_SET)
  167. -        goto out;
  168. -
  169.      status = safe_write(&buffer, length, &len, sizeof(len));
  170.      if (status) goto out;
  171.  
  172. @@ -311,7 +256,7 @@ static int marshall_symlink(unsigned char *buffer, uint32_t *length, nfs41_upcal
  173.              MB_ERR_INVALID_CHARS,
  174.              args->target_get.path, args->target_get.len,
  175.              (LPWSTR)buffer, len / sizeof(WCHAR))) {
  176. -        eprintf("marshall_symlink: "
  177. +        eprintf("marshall_symlink_get: "
  178.              "MultiByteToWideChar() failed, lasterr=%d\n",
  179.              (int)GetLastError());
  180.          status = ERROR_BUFFER_OVERFLOW;
  181. @@ -323,15 +268,104 @@ out:
  182.  
  183.  
  184.  const nfs41_upcall_op nfs41_op_symlink_get = {
  185. -    .parse = parse_symlink,
  186. -    .handle = handle_symlink,
  187. -    .marshall = marshall_symlink,
  188. +    .parse = parse_symlink_get,
  189. +    .handle = handle_symlink_get,
  190. +    .marshall = marshall_symlink_get,
  191.      .arg_size = sizeof(symlink_upcall_args)
  192.  };
  193.  
  194. +/* NFS41_SYSOP_SYMLINK_SET */
  195. +static int parse_symlink_set(unsigned char *buffer, uint32_t length,
  196. +    nfs41_upcall *upcall)
  197. +{
  198. +    symlink_upcall_args *args = &upcall->args.symlink;
  199. +    int status;
  200. +
  201. +    status = get_name(&buffer, &length, &args->path);
  202. +    if (status)
  203. +        goto out;
  204. +
  205. +    /*
  206. +     * args->target_set is not const because |handle_symlink_set()|
  207. +     * might have to replace '\\' with '/'
  208. +     */
  209. +    status = get_name(&buffer, &length,
  210. +        (const char **)(&args->target_set));
  211. +
  212. +    DPRINTF(1,
  213. +        ("parse_symlink_set: parsing NFS41_SYSOP_SYMLINK_SET: "
  214. +        "path='%s' target='%s'\n",
  215. +        args->path, args->target_set));
  216. +
  217. +out:
  218. +    return status;
  219. +}
  220. +
  221. +static int handle_symlink_set(void *daemon_context, nfs41_upcall *upcall)
  222. +{
  223. +    symlink_upcall_args *args = &upcall->args.symlink;
  224. +    nfs41_open_state *state = upcall->state_ref;
  225. +    int status = NO_ERROR;
  226. +
  227. +    nfs41_file_info info, createattrs;
  228. +
  229. +    /* don't send windows slashes to the server */
  230. +    char *p;
  231. +    for (p = args->target_set; *p; p++) {
  232. +        if (*p == '\\') *p = '/';
  233. +    }
  234. +
  235. +    if (state->file.fh.len) {
  236. +        /*
  237. +         * the check in handle_open() didn't catch that we're creating
  238. +         * a symlink, so we have to remove the file it already created
  239. +         */
  240. +        eprintf("handle_symlink_set: "
  241. +            "attempting to create a symlink when "
  242. +            "the file='%s' was already created on open; sending "
  243. +            "REMOVE first\n", state->file.path->path);
  244. +        status = nfs41_remove(state->session, &state->parent,
  245. +            &state->file.name, state->file.fh.fileid);
  246. +        if (status) {
  247. +            eprintf("handle_symlink_set: "
  248. +                "nfs41_remove() for symlink='%s' failed with '%s'\n",
  249. +                args->target_set, nfs_error_string(status));
  250. +            status = map_symlink_errors(status);
  251. +            goto out;
  252. +        }
  253. +    }
  254. +
  255. +    /* create the symlink */
  256. +    createattrs.attrmask.count = 2;
  257. +    createattrs.attrmask.arr[0] = 0;
  258. +    createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE;
  259. +    createattrs.mode = 0777;
  260. +
  261. +    /* FIXME: What about newgrp support ? */
  262. +
  263. +    status = nfs41_create(state->session, NF4LNK, &createattrs,
  264. +        args->target_set, &state->parent, &state->file, &info);
  265. +    if (status) {
  266. +        eprintf("handle_symlink_set: "
  267. +            "nfs41_create() for symlink='%s' failed with '%s'\n",
  268. +            args->target_set, nfs_error_string(status));
  269. +        status = map_symlink_errors(status);
  270. +        goto out;
  271. +    }
  272. +
  273. +out:
  274. +    return status;
  275. +}
  276. +
  277. +static int marshall_symlink_set(unsigned char *buffer, uint32_t *length,
  278. +    nfs41_upcall *upcall)
  279. +{
  280. +    return NO_ERROR;
  281. +}
  282. +
  283.  const nfs41_upcall_op nfs41_op_symlink_set = {
  284. -    .parse = parse_symlink,
  285. -    .handle = handle_symlink,
  286. -    .marshall = marshall_symlink,
  287. +    .parse = parse_symlink_set,
  288. +    .handle = handle_symlink_set,
  289. +    .marshall = marshall_symlink_set,
  290.      .arg_size = sizeof(symlink_upcall_args)
  291.  };
  292. --
  293. 2.45.1
  294.  
  295. From 405dee2f37fd0d5ec43d428ebd08752606250c6c Mon Sep 17 00:00:00 2001
  296. From: Roland Mainz <roland.mainz@nrubsig.org>
  297. Date: Thu, 6 Feb 2025 12:41:07 +0100
  298. Subject: [PATCH 2/3] sys,tests: Fix cmd.exe mklink relative links
  299.  
  300. Fix cmd.exe mklink relative links, e.g.
  301. $ cmd /C 'mklink /D targetdir1_sym targetdir1' # should work + add
  302. testcases
  303.  
  304. Reported-by: Lionel Cons <lionelcons1972@gmail.com>
  305. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  306. ---
  307. sys/nfs41sys_symlink.c   | 43 +++++++++++++++++++++++++++++++---------
  308.  tests/manual_testing.txt |  4 ++++
  309.  2 files changed, 38 insertions(+), 9 deletions(-)
  310.  
  311. diff --git a/sys/nfs41sys_symlink.c b/sys/nfs41sys_symlink.c
  312. index eea2db8..8f4447b 100644
  313. --- a/sys/nfs41sys_symlink.c
  314. +++ b/sys/nfs41sys_symlink.c
  315. @@ -293,17 +293,15 @@ NTSTATUS nfs41_SetSymlinkReparsePoint(
  316.              "absolute path TargetName='%wZ'\n",
  317.              &TargetName);
  318.  
  319. -        /* Strip "\\??\\" prefix */
  320. -        if (!memcmp(&TargetName.Buffer[0], L"\\??\\",
  321. -            (4*sizeof(wchar_t)))) {
  322. +        /* UNC path ? */
  323. +        if ((TargetName.Length > 8*sizeof(wchar_t)) &&
  324. +            (!memcmp(&TargetName.Buffer[0], L"\\??\\UNC\\",
  325. +            (8*sizeof(wchar_t))))) {
  326. +
  327. +            /* Strip "\\??\\" prefix */
  328.              TargetName.Buffer += 4;
  329.              TargetName.MaximumLength = TargetName.Length =
  330.                  TargetName.Length-(4*sizeof(wchar_t));
  331. -        }
  332. -
  333. -        /* UNC path ? */
  334. -        if (!memcmp(&TargetName.Buffer[0], L"UNC\\",
  335. -            (4*sizeof(wchar_t)))) {
  336.  
  337.              /*
  338.               * Turn "UNC\" into "\\"
  339. @@ -319,13 +317,22 @@ NTSTATUS nfs41_SetSymlinkReparsePoint(
  340.                  "UNC TargetName='%wZ'\n",
  341.                  &TargetName);
  342.          }
  343. -        else {
  344. +        /* DEVICELETTR path ? */
  345. +        else if ((TargetName.Length >= 6*sizeof(wchar_t)) &&
  346. +            (!memcmp(&TargetName.Buffer[0], L"\\??\\",
  347. +            (4*sizeof(wchar_t)))) &&
  348. +            (TargetName.Buffer[5] == L':')) {
  349.              wchar_t devletter;
  350.  
  351.              DbgP("nfs41_SetSymlinkReparsePoint: "
  352.                  "DEVLETTER TargetName='%wZ'\n",
  353.                  &TargetName);
  354.  
  355. +            /* Strip "\\??\\" prefix */
  356. +            TargetName.Buffer += 4;
  357. +            TargetName.MaximumLength = TargetName.Length =
  358. +                TargetName.Length-(4*sizeof(wchar_t));
  359. +
  360.              if ((TargetName.Buffer[1] != L':') ||
  361.                  (TargetName.Buffer[2] != L'\\')) {
  362.                  status = STATUS_INVALID_PARAMETER;
  363. @@ -374,6 +381,24 @@ NTSTATUS nfs41_SetSymlinkReparsePoint(
  364.                  "new TargetName='%wZ'\n",
  365.                  &TargetName);
  366.          }
  367. +        else if ((TargetName.Length > 1*sizeof(wchar_t)) &&
  368. +            (
  369. +                (TargetName.Buffer[0] == L'\\') ||
  370. +                (TargetName.Buffer[0] == L'/') ||
  371. +                (TargetName.Buffer[0] == L':')
  372. +            )) {
  373. +            DbgP("nfs41_SetSymlinkReparsePoint: "
  374. +                "TargetName='%wZ' should not start "
  375. +                "with '/', '\\' or ':'\n",
  376. +                &TargetName);
  377. +            status = STATUS_INVALID_PARAMETER;
  378. +            goto out;
  379. +        }
  380. +        else {
  381. +            DbgP("nfs41_SetSymlinkReparsePoint: "
  382. +                "relative symlink TargetName='%wZ'\n",
  383. +                &TargetName);
  384. +        }
  385.      }
  386.  
  387.      status = nfs41_UpcallCreate(NFS41_SYSOP_SYMLINK_SET, &Fobx->sec_ctx,
  388. diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
  389. index f8a006c..173c753 100644
  390. --- a/tests/manual_testing.txt
  391. +++ b/tests/manual_testing.txt
  392. @@ -179,6 +179,10 @@ powershell -Command 'New-Item -Path sym_mypsdir1 -ItemType SymbolicLink -Value m
  393.  # 4. powershell mklink file
  394.  mkdir mypsfile1
  395.  powershell -Command 'New-Item -Path sym_mypsfile1 -ItemType SymbolicLink -Value mypsfile1'
  396. +# 5. Relative links:
  397. +mkdir targetdir1
  398. +cmd /C 'mklink /D targetdir1_sym targetdir1'
  399. +cmd /C 'mklink /D targetdir2_sym .\targetdir1'
  400.  
  401.  #
  402.  # Tests for groups
  403. --
  404. 2.45.1
  405.  
  406. From b52dad8aecf95ed8e32b6b3df66d1d7b77c965ec Mon Sep 17 00:00:00 2001
  407. From: Roland Mainz <roland.mainz@nrubsig.org>
  408. Date: Thu, 6 Feb 2025 14:53:12 +0100
  409. Subject: [PATCH 3/3] daemon: |abs_path_link()| should preserve link's UNC
  410.  prefix ("\\") in path argument
  411.  
  412. |abs_path_link()| should preserve link's UNC prefix ("\\") in path
  413. argument
  414.  
  415. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  416. ---
  417. daemon/symlink.c | 26 +++++++++++++++++++++++++-
  418.  1 file changed, 25 insertions(+), 1 deletion(-)
  419.  
  420. diff --git a/daemon/symlink.c b/daemon/symlink.c
  421. index 4eeece3..59894e2 100644
  422. --- a/daemon/symlink.c
  423. +++ b/daemon/symlink.c
  424. @@ -43,9 +43,21 @@ static int abs_path_link(
  425.      const char *link_end = link + link_len;
  426.      int status = NO_ERROR;
  427.  
  428. +    DPRINTF(2,
  429. +        ("--> abs_path_link(path_pos='%s', link='%.*s', link_len=%d)\n",
  430. +        path_pos, (int)link_len, link, (int)link_len));
  431. +
  432. +    /* UNC path ? Make sure we return \\... */
  433. +    if ((link_len > 2) && (!memcmp(link, "//", 2))) {
  434. +        path->path[0] = '\\';
  435. +        path->path[1] = '\\';
  436. +        path_pos = path->path+2;
  437. +        link_pos += 2;
  438. +    }
  439.      /* if link is an absolute path, start path_pos at the beginning */
  440. -    if (is_delimiter(*link))
  441. +    else if (is_delimiter(*link)) {
  442.          path_pos = path->path;
  443. +    }
  444.  
  445.      /* copy each component of link into the path */
  446.      while (next_component(link_pos, link_end, &name)) {
  447. @@ -89,6 +101,18 @@ static int abs_path_link(
  448.      *path_pos = '\0';
  449.  out:
  450.      path->len = (unsigned short)(path_pos - path->path);
  451. +
  452. +    if (status) {
  453. +        DPRINTF(2,
  454. +            ("<-- abs_path_link(), status=%d\n",
  455. +            status));
  456. +    }
  457. +    else {
  458. +        DPRINTF(2,
  459. +            ("<-- abs_path_link(path='%.*s'), status=%d\n",
  460. +            (int)path->len, path->path, status));
  461. +    }
  462. +
  463.      return status;
  464.  }
  465.  
  466. --
  467. 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