ok,

<< What do you mean by "logical" file name resolution? >>
"logical" is the boolean variable define in the file we talk about : "lib/canonicalize.c"
line 187 : bool logical = ...;

<< "NOLINKS" flag - what do you mean by that? >>
"CAN_NOLINKS" is a flag that modifs "logical" boolean variable in the file we talk about : "lib/canonicalize.c"
line 187 : bool logical = (can_mode & CAN_NOLINKS) != 0;

<< "current-directory is a symbolic-link" - what do you mean by that? >>
suppose "/tmp/logical_dir" is a symbolic-link to directory "/tmp/phisical_dir". if you change directory to "/tmp/logical_dir", then "current-directory is a symbolic-link"
example script :
 {
  mkdir -p /tmp/phisical_dir
  ln -sf phisical_dir /tmp/logical_dir
  cd -L /tmp/logical_dir
  pwd
 }

I have attache a new version of my commit-proposal including a section "How to reproduce".


about unit-test :
- here is the use-case I wanted to add in "tests/test-canonicalize.c" around line 430 :
 /* Check that "." and "$PWD" result the same way */
  {
    ASSERT (0 == chdir(BASE "/s"));
    char *wd = get_current_dir_name();
    char *result1 = canonicalize_filename_mode ( ".", 0);
    char *result2 = canonicalize_filename_mode ( ".", CAN_NOLINKS);
    char *result3 = canonicalize_filename_mode ( wd, 0);
    char *result4 = canonicalize_filename_mode ( wd, CAN_NOLINKS);
    ASSERT (0 == chdir("../.."));
    ASSERT (result1 != NULL);
    ASSERT (result2 != NULL);
    ASSERT (result3 != NULL);
    ASSERT (result4 != NULL);
    ASSERT (str_endswith (wd, "/" BASE "/s"));
    ASSERT (str_startswith (result1, wd));
    ASSERT (str_startswith (result2, wd));
    ASSERT (str_startswith (result3, wd));
    ASSERT (str_startswith (result4, wd));
    ASSERT (str_endswith (result1, "/" BASE "/d"));
    ASSERT (0 == strcmp (result1, result2));
    ASSERT (0 == strcmp (result1, result3));
    ASSERT (str_endswith (result4, "/" BASE "/s"));
    free (wd);
    free (result1);
    free (result2);
    free (result3);
    free (result4);
  }
- but this test does not work due to chdir(BASE "/s") that behave as
  chdir(BASE "/d") in the test-context.
- feel free to have a look but I did not found any C langage workaround.
- I did a working unit-test on coreutil realpath executable. I attach the
  corresponding commit to this post.

Patrick


On 01/11/2025 12:58, Bruno Haible wrote:
Hi,

Patrick GARCIA wrote:
I did not manage to use "vc-dwim" properly.
vc-dwim is used to create a ChangeLog entry. When you provide a patch
with a reasonable git commit message, we can easily turn that into
a ChangeLog entry. Therefore, no real need to use 'vc-dwim'.

When you propose a patch, you should provide an explanation regarding
the situation where it provides an improvement.

   - Which OS? I guess GNU/Linux, but you should better state that
     explicitly.
   - What are the "How to reproduce" instructions?

Your git commit message gives only partial answers:

   - What do you mean by "logical" file name resolution?
   - "NOLINKS" flag - what do you mean by that?
   - "current-directory is a sybolic-link" - what do you mean by that?
     When a process enters a directory via chdir(), is follows symbolic
     links. Therefore the current directory is _never_ a symbolic link,
     it is _always_ a real directory.

PS : I will, then, propose a shell unit-test to the coreutils team.
Ideally, since Gnulib is a C functions library, the unit test should
be a small self-contained C program. That test program lives in
gnulib/tests/.

Bruno


From 878f29266f73a15d9a7592cb0b0df33fe8bc3754 Mon Sep 17 00:00:00 2001
From: Patrick GARCIA <[email protected]>
Date: Fri, 31 Oct 2025 18:20:34 +0100
Subject: [PATCH] Fix canonicalize_filename_mode_stk() when current-directory
 is a symlink

* lib/canonicalize.c: modify canonicalize_filename_mode_stk()
  when logical resolution (NOLINKS mode is set) and current-directory is a
  symlink. in this case current-directory should be resolved as "${PWD}".

How to reproduce :
- on rockylinux 9.4
- start the bash script :
 {
  echo "--- prepare ---"
  mkdir -p /tmp/phisical_dir
  ln -sf phisical_dir /tmp/logical_dir
  cd -L /tmp/logical_dir
  echo "--- check ---"
  ls -ld /tmp/*_dir
  [ "/tmp/logical_dir" == "$(realpath -sm "${PWD}")" ] && echo "ok as expected" || echo "bug!"
  [ "/tmp/logical_dir" == "$(realpath -sm ".")"      ] && echo "ok as expected" || echo "bug!"
  realpath -sm "${PWD}" "."
 }
- directory "${PWD}" and "." should return the same value "/tmp/logical_dir" while using : realpath -sm


no unit test can compile in C because chdir() refuse tu switch to a
sybolic-link-directory. a unit test is provided in coreutils project, for
realpath executable as this unit test is a shell script.
---
 lib/canonicalize.c | 36 ++++++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 10d85ef..c437b1d 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -216,22 +216,30 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
 
   if (!IS_ABSOLUTE_FILE_NAME (name))
     {
-      while (!getcwd (bufs->rname.data, bufs->rname.length))
-        {
-          switch (errno)
+        if (logical) {
+            /* use "naiv" PWD env var */
+            char *cwd = get_current_dir_name();
+            strncpy (bufs->rname.data, cwd, bufs->rname.length);
+            free(cwd);
+        } else {
+            /* resolve phisical working dir */
+          while (!getcwd (bufs->rname.data, bufs->rname.length))
             {
-            case ERANGE:
-              if (scratch_buffer_grow (&bufs->rname))
-                break;
-              FALLTHROUGH;
-            case ENOMEM:
-              xalloc_die ();
-
-            default:
-              dest = rname;
-              goto error;
+              switch (errno)
+                {
+                case ERANGE:
+                  if (scratch_buffer_grow (&bufs->rname))
+                    break;
+                  FALLTHROUGH;
+                case ENOMEM:
+                  xalloc_die ();
+
+                default:
+                  dest = rname;
+                  goto error;
+                }
+              rname = bufs->rname.data;
             }
-          rname = bufs->rname.data;
         }
       dest = rawmemchr (rname, '\0');
       start = name;
-- 
2.30.2

From dd08cabf47efe13247046738e00822d7da8e3ee3 Mon Sep 17 00:00:00 2001
From: Patrick GARCIA <[email protected]>
Date: Fri, 31 Oct 2025 18:17:23 +0100
Subject: [PATCH] Test current-directory resolution bug in realpath

* tests/misc/realpath.sh: add use case in realpath unit-test to check that
  << realpath -s "." >> result is "$PWD" event when current-directory is a
  symlink
---
 tests/misc/realpath.sh | 81 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/tests/misc/realpath.sh b/tests/misc/realpath.sh
index 3ba9bd3..43f8a3f 100755
--- a/tests/misc/realpath.sh
+++ b/tests/misc/realpath.sh
@@ -111,4 +111,85 @@ else
   test "$out" = ".$nl." || fail=1
 fi
 
+
+
+
+
+# when call "realpath . $(pwd)", the two results should be equals what ever
+# additional options.
+
+rm -fr "${PWD}/one_link" "${PWD}/one_directory"
+mkdir -pv "${PWD}/one_directory"
+ln -sv "${PWD}/one_directory" "${PWD}/one_link"
+
+actual="
+$(
+for wd   in "${PWD}/one_directory" "${PWD}/one_link" ; do
+for opt  in "" -s -m -sm ; do
+ echo ""
+ cmd="cd '${wd}' ; realpath ${opt} '${wd}' . a a/b 2>&1"
+ echo "${cmd}"
+ LANG=C bash -c "${cmd}"
+done
+done
+)
+"
+
+expected="
+
+cd '${PWD}/one_directory' ; realpath  '${PWD}/one_directory' . a a/b 2>&1
+${PWD}/one_directory
+${PWD}/one_directory
+${PWD}/one_directory/a
+realpath: a/b: No such file or directory
+
+cd '${PWD}/one_directory' ; realpath -s '${PWD}/one_directory' . a a/b 2>&1
+${PWD}/one_directory
+${PWD}/one_directory
+${PWD}/one_directory/a
+${PWD}/one_directory/a/b
+
+cd '${PWD}/one_directory' ; realpath -m '${PWD}/one_directory' . a a/b 2>&1
+${PWD}/one_directory
+${PWD}/one_directory
+${PWD}/one_directory/a
+${PWD}/one_directory/a/b
+
+cd '${PWD}/one_directory' ; realpath -sm '${PWD}/one_directory' . a a/b 2>&1
+${PWD}/one_directory
+${PWD}/one_directory
+${PWD}/one_directory/a
+${PWD}/one_directory/a/b
+
+cd '${PWD}/one_link' ; realpath  '${PWD}/one_link' . a a/b 2>&1
+${PWD}/one_directory
+${PWD}/one_directory
+${PWD}/one_directory/a
+realpath: a/b: No such file or directory
+
+cd '${PWD}/one_link' ; realpath -s '${PWD}/one_link' . a a/b 2>&1
+${PWD}/one_link
+${PWD}/one_link
+${PWD}/one_link/a
+${PWD}/one_link/a/b
+
+cd '${PWD}/one_link' ; realpath -m '${PWD}/one_link' . a a/b 2>&1
+${PWD}/one_directory
+${PWD}/one_directory
+${PWD}/one_directory/a
+${PWD}/one_directory/a/b
+
+cd '${PWD}/one_link' ; realpath -sm '${PWD}/one_link' . a a/b 2>&1
+${PWD}/one_link
+${PWD}/one_link
+${PWD}/one_link/a
+${PWD}/one_link/a/b
+"
+
+#echo "${actual}"
+diff <(echo "${actual}") <(echo "${expected}") -C 2 || {
+ fail=1
+ sdiff <(echo "${actual}") <(echo "${expected}") --width=150
+}
+
 Exit $fail
-- 
2.30.2

Reply via email to