canonicalize_file_name does not support MS-Windows style file names

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 | Next >

canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

With the patch below, it does.

HTH

--- lib/canonicalize-lgpl.c~0 2011-10-22 16:19:34.000000000 +0200
+++ lib/canonicalize-lgpl.c 2012-01-17 13:10:52.608428500 +0200
@@ -51,6 +51,7 @@
 # define __realpath realpath
 # include "pathmax.h"
 # include "malloca.h"
+# include "dosname.h"
 # if HAVE_GETCWD
 #  if IN_RELOCWRAPPER
     /* When building the relocatable program wrapper, use the system's getcwd
@@ -101,6 +102,7 @@ __realpath (const char *name, char *reso
   const char *start, *end, *rpath_limit;
   long int path_max;
   int num_links = 0;
+  size_t prefix_len;
 
   if (name == NULL)
     {
@@ -143,7 +145,11 @@ __realpath (const char *name, char *reso
     rpath = resolved;
   rpath_limit = rpath + path_max;
 
-  if (name[0] != '/')
+  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
+     and MS-DOS X:/foo/bar file names.  */
+  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+
+  if (!IS_ABSOLUTE_FILE_NAME (name))
     {
       if (!__getcwd (rpath, path_max))
         {
@@ -154,13 +160,19 @@ __realpath (const char *name, char *reso
     }
   else
     {
-      rpath[0] = '/';
-      dest = rpath + 1;
-      if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/')
+      dest = rpath;
+      if (prefix_len)
+ {
+  memcpy (rpath, name, prefix_len);
+  dest += prefix_len;
+ }
+      *dest++ = '/';
+      if (DOUBLE_SLASH_IS_DISTINCT_ROOT && ISSLASH (name[1])
+  && !prefix_len)
         *dest++ = '/';
     }
 
-  for (start = end = name; *start; start = end)
+  for (start = end = name + prefix_len; *start; start = end)
     {
 #ifdef _LIBC
       struct stat64 st;
@@ -170,11 +182,11 @@ __realpath (const char *name, char *reso
       int n;
 
       /* Skip sequence of multiple path-separators.  */
-      while (*start == '/')
+      while (ISSLASH (*start))
         ++start;
 
       /* Find end of path component.  */
-      for (end = start; *end && *end != '/'; ++end)
+      for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
       if (end - start == 0)
@@ -184,7 +196,7 @@ __realpath (const char *name, char *reso
       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
         {
           /* Back up to previous component, ignore if at root already.  */
-          if (dest > rpath + 1)
+          if (dest > rpath + prefix_len + 1)
             while ((--dest)[-1] != '/');
           if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
               && *dest == '/')
@@ -205,7 +217,7 @@ __realpath (const char *name, char *reso
               if (resolved)
                 {
                   __set_errno (ENAMETOOLONG);
-                  if (dest > rpath + 1)
+                  if (dest > rpath + prefix_len + 1)
                     dest--;
                   *dest = '\0';
                   goto error;
@@ -295,17 +307,25 @@ __realpath (const char *name, char *reso
               memmove (&extra_buf[n], end, len + 1);
               name = end = memcpy (extra_buf, buf, n);
 
-              if (buf[0] == '/')
+              if (IS_ABSOLUTE_FILE_NAME (buf))
                 {
-                  dest = rpath + 1;     /* It's an absolute symlink */
-                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/')
+  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
+
+  if (pfxlen)
+    memcpy (rpath, buf, pfxlen);
+                  dest = rpath + pfxlen;     /* It's an absolute symlink.  */
+  *dest++ = '/';
+                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && ISSLASH (buf[1])
+      && pfxlen == 0)
                     *dest++ = '/';
+  /* Install the new prefix to be in effect hereafter.  */
+  prefix_len = pfxlen;
                 }
               else
                 {
                   /* Back up to previous component, ignore if at root
                      already: */
-                  if (dest > rpath + 1)
+                  if (dest > rpath + prefix_len + 1)
                     while ((--dest)[-1] != '/');
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
                       && *dest == '/')
@@ -319,7 +339,7 @@ __realpath (const char *name, char *reso
             }
         }
     }
-  if (dest > rpath + 1 && dest[-1] == '/')
+  if (dest > rpath + prefix_len + 1 && dest[-1] == '/')
     --dest;
   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && *dest == '/')
     dest++;



Re: canonicalize_file_name does not support MS-Windows style file names

by Bruno Haible :: Rate this Message:

| View Threaded | Show Only this Message

Hi Eli,

> With the patch below, it does.

Thanks, I'll look into integrating it.

Do you also have a set of Windows-syntax filenames available on which you
tested it? So that we can extend the unit test.

Btw, this is your first major contribution to Gnulib. Would you mind
starting the copyright assigment process, like you did for so many other
GNU packages?

Bruno



Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> From: Bruno Haible <bruno@...>
> Bcc: bruno@...
> Date: Tue, 17 Jan 2012 20:07:11 +0100
>
> Thanks, I'll look into integrating it.

Thanks, looking forward to it.

> Do you also have a set of Windows-syntax filenames available on which you
> tested it? So that we can extend the unit test.

I don't have a test set, although I can craft one.  My test case was
Guile.

> Btw, this is your first major contribution to Gnulib. Would you mind
> starting the copyright assigment process, like you did for so many other
> GNU packages?

It's already in the works, I snailed the papers last weekend.


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> Date: Tue, 17 Jan 2012 22:04:38 +0200
> From: Eli Zaretskii <eliz@...>
> CC: bug-gnulib@...
>
> > From: Bruno Haible <bruno@...>
> > Bcc: bruno@...
> > Date: Tue, 17 Jan 2012 20:07:11 +0100
> >
> > Thanks, I'll look into integrating it.
>
> Thanks, looking forward to it.
>
> > Do you also have a set of Windows-syntax filenames available on which you
> > tested it? So that we can extend the unit test.
>
> I don't have a test set, although I can craft one.  My test case was
> Guile.
>
> > Btw, this is your first major contribution to Gnulib. Would you mind
> > starting the copyright assigment process, like you did for so many other
> > GNU packages?
>
> It's already in the works, I snailed the papers last weekend.

Any reasons why that patch (see
http://lists.gnu.org/archive/html/bug-gnulib/2012-01/msg00253.html)
was not yet integrated?  If you were waiting for the paperwork, it was
completed months ago, see copyright.list.

TIA


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> Date: Tue, 19 Jun 2012 18:55:02 +0300
> From: Eli Zaretskii <eliz@...>
> CC: bug-gnulib@...
>
> > Date: Tue, 17 Jan 2012 22:04:38 +0200
> > From: Eli Zaretskii <eliz@...>
> > CC: bug-gnulib@...
> >
> > > From: Bruno Haible <bruno@...>
> > > Bcc: bruno@...
> > > Date: Tue, 17 Jan 2012 20:07:11 +0100
> > >
> > > Thanks, I'll look into integrating it.
> >
> > Thanks, looking forward to it.
> >
> > > Do you also have a set of Windows-syntax filenames available on which you
> > > tested it? So that we can extend the unit test.
> >
> > I don't have a test set, although I can craft one.  My test case was
> > Guile.
> >
> > > Btw, this is your first major contribution to Gnulib. Would you mind
> > > starting the copyright assigment process, like you did for so many other
> > > GNU packages?
> >
> > It's already in the works, I snailed the papers last weekend.
>
> Any reasons why that patch (see
> http://lists.gnu.org/archive/html/bug-gnulib/2012-01/msg00253.html)
> was not yet integrated?  If you were waiting for the paperwork, it was
> completed months ago, see copyright.list.
>
> TIA

Ping!


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

Ping!  (6 months)

> Date: Tue, 19 Jun 2012 18:55:02 +0300
> From: Eli Zaretskii <eliz@...>
> CC: bug-gnulib@...
>
> > Date: Tue, 17 Jan 2012 22:04:38 +0200
> > From: Eli Zaretskii <eliz@...>
> > CC: bug-gnulib@...
> >
> > > From: Bruno Haible <bruno@...>
> > > Bcc: bruno@...
> > > Date: Tue, 17 Jan 2012 20:07:11 +0100
> > >
> > > Thanks, I'll look into integrating it.
> >
> > Thanks, looking forward to it.
> >
> > > Do you also have a set of Windows-syntax filenames available on which you
> > > tested it? So that we can extend the unit test.
> >
> > I don't have a test set, although I can craft one.  My test case was
> > Guile.
> >
> > > Btw, this is your first major contribution to Gnulib. Would you mind
> > > starting the copyright assigment process, like you did for so many other
> > > GNU packages?
> >
> > It's already in the works, I snailed the papers last weekend.
>
> Any reasons why that patch (see
> http://lists.gnu.org/archive/html/bug-gnulib/2012-01/msg00253.html)
> was not yet integrated?  If you were waiting for the paperwork, it was
> completed months ago, see copyright.list.
>
> TIA


Re: canonicalize_file_name does not support MS-Windows style file names

by Mark H Weaver :: Rate this Message:

| View Threaded | Show Only this Message

Hi,

Guile needs Eli's patch in order build under mingw + msys, which is
important for several cross-platform programs that depend on libguile.
We hope to release Guile 2.0.7 in the week of Nov 26, so it would be
great if this patch could be integrated soon.

Eli, I see that Bruno asked for a set of Windows-syntax filenames to
extend the unit test.  Would you be willing to work on that?

     Mark


Eli Zaretskii <eliz@...> writes:

> Ping!  (6 months)
>
>> Date: Tue, 19 Jun 2012 18:55:02 +0300
>> From: Eli Zaretskii <eliz@...>
>> CC: bug-gnulib@...
>>
>> > Date: Tue, 17 Jan 2012 22:04:38 +0200
>> > From: Eli Zaretskii <eliz@...>
>> > CC: bug-gnulib@...
>> >
>> > > From: Bruno Haible <bruno@...>
>> > > Bcc: bruno@...
>> > > Date: Tue, 17 Jan 2012 20:07:11 +0100
>> > >
>> > > Thanks, I'll look into integrating it.
>> >
>> > Thanks, looking forward to it.
>> >
>> > > Do you also have a set of Windows-syntax filenames available on which you
>> > > tested it? So that we can extend the unit test.
>> >
>> > I don't have a test set, although I can craft one.  My test case was
>> > Guile.
>> >
>> > > Btw, this is your first major contribution to Gnulib. Would you mind
>> > > starting the copyright assigment process, like you did for so many other
>> > > GNU packages?
>> >
>> > It's already in the works, I snailed the papers last weekend.
>>
>> Any reasons why that patch (see
>> http://lists.gnu.org/archive/html/bug-gnulib/2012-01/msg00253.html)
>> was not yet integrated?  If you were waiting for the paperwork, it was
>> completed months ago, see copyright.list.
>>
>> TIA


Re: canonicalize_file_name does not support MS-Windows style file names

by Paul Eggert :: Rate this Message:

| View Threaded | Show Only this Message

We've mostly been relying on Bruno to review patches like that,
as he has the expertise and the desire to support Windows.
Unfortunately Bruno has been busy lately.  I suggest that
if we don't hear from him soon, that we apply the
patch to Gnulib.  Guile can do that now to its copy of
lib/canonicalize-lgpl.c, if it likes.


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> From: Mark H Weaver <mhw@...>
> Cc: bruno@..., bug-gnulib@...
> Date: Wed, 07 Nov 2012 08:07:04 -0500
>
> Guile needs Eli's patch in order build under mingw + msys, which is
> important for several cross-platform programs that depend on libguile.
> We hope to release Guile 2.0.7 in the week of Nov 26, so it would be
> great if this patch could be integrated soon.

I cannot agree more.  The patch was submitted in January(!).

> Eli, I see that Bruno asked for a set of Windows-syntax filenames to
> extend the unit test.  Would you be willing to work on that?

I can come up with file names that could be used to test the code, if
this will help, but I won't have resources to make a complete patch
for the unit test program(s), sorry.

I just hope that whatever I submit in addition to what I already did
will not be left collecting dust for another year.


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> Date: Wed, 07 Nov 2012 07:30:03 -0800
> From: Paul Eggert <eggert@...>
> CC: Eli Zaretskii <eliz@...>, bug-gnulib@..., bruno@...
>
> I suggest that if we don't hear from [Bruno] soon, that we apply the
> patch to Gnulib.

Thank you, I'd appreciate that.


Re: canonicalize_file_name does not support MS-Windows style file names

by Mark H Weaver :: Rate this Message:

| View Threaded | Show Only this Message

Hi Eli,

Eli Zaretskii <eliz@...> writes:
>> Eli, I see that Bruno asked for a set of Windows-syntax filenames to
>> extend the unit test.  Would you be willing to work on that?
>
> I can come up with file names that could be used to test the code, if
> this will help, but I won't have resources to make a complete patch
> for the unit test program(s), sorry.

That would be very helpful!  Hopefully the rest will be an easy job for
someone familiar with the gnulib unit tests, but if no one steps
forward, I'll do it.

> I just hope that whatever I submit in addition to what I already did
> will not be left collecting dust for another year.

I'll do what I can to prevent that outcome.  Hopefully Paul can help us
get your patch committed.

   Many thanks,
      Mark


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> From: Mark H Weaver <mhw@...>
> Cc: Paul Eggert <eggert@...>, bruno@...,  bug-gnulib@...
> Date: Wed, 07 Nov 2012 22:49:36 -0500
>
> Eli Zaretskii <eliz@...> writes:
> >> Eli, I see that Bruno asked for a set of Windows-syntax filenames to
> >> extend the unit test.  Would you be willing to work on that?
> >
> > I can come up with file names that could be used to test the code, if
> > this will help, but I won't have resources to make a complete patch
> > for the unit test program(s), sorry.
>
> That would be very helpful!

Sorry for the delay.  I found that the sources changed in gnulib since
I patched them, so I went back and redid the changes relative to the
current version.  You will find below, in addition to the test cases
and the test program I used, also patches for both canonicalize-lgpl.c
and canonicalize.c.

> Hopefully the rest will be an easy job for someone familiar with the
> gnulib unit tests, but if no one steps forward, I'll do it.
>
> > I just hope that whatever I submit in addition to what I already did
> > will not be left collecting dust for another year.
>
> I'll do what I can to prevent that outcome.  Hopefully Paul can help us
> get your patch committed.

Thanks.  Looking forward to see this resolved.

Here are the test cases I tried and their results.  My current
directory when running these tests was d:\usr\eli\utils\CURDIR.

     'foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '.\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     './foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\foo.bar' => 'd:\usr\eli\utils\foo.bar'
     '../foo.bar' => 'd:\usr\eli\utils\foo.bar'
     '../CURDIR/foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\CURDIR\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\CURDIR/foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\CURDIR\foo.bar\' => '(null)'
     '../CURDIR\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     'C:WINDOWS' => '(null)'
     'C:system32' => '(null)'
     'C:/WINDOWS' => 'C:/WINDOWS'
     'C:\WINDOWS' => 'C:/WINDOWS'
     'C:\\WINDOWS' => 'C:/WINDOWS'
     'C:./WINDOWS' => '(null)'
     'C:./system32' => '(null)'
     'C:.\WINDOWS' => '(null)'
     'C:.\system32' => '(null)'
     'C:.' => 'd:\usr\eli\utils\lib'
     'C:/' => 'C:/'
     'C:\' => 'C:/'

The "(null)" results are failures, and they all mean one thing: the
patched functions still do not support drive-relative file names.  I
don't consider it a significant omission, since these names are very
rare, and OTOH supporting them would require much more invasive
changes in the original gnulib code.  So I decided to omit that.

Here's the test program I used:

  /* Before running, type: "cd C:\WINDOWS" at the shell prompt.  */

  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <string.h>

  extern char * canonicalize_file_name (const char *);

  int
  main (void)
  {
    const char *test_fname[] = {
      "foo.bar",
      ".\\foo.bar",
      "./foo.bar",
      "..\\foo.bar",
      "../foo.bar",
      "../%s/foo.bar",
      "..\\%s\\foo.bar",
      "..\\%s/foo.bar",
      "..\\%s\\foo.bar\\",
      "../%s\\foo.bar",
      "C:WINDOWS",
      "C:system32",
      "C:/WINDOWS",
      "C:\\WINDOWS",
      "C:\\\\WINDOWS",
      "C:./WINDOWS",
      "C:./system32",
      "C:.\\WINDOWS",
      "C:.\\system32",
      "C:.",
      "C:/",
      "C:\\"
    };
    int i;
    char curdir[MAX_PATH], *pc;
    getcwd (curdir, MAX_PATH);
    for (pc = curdir + strlen (curdir); !ISSLASH (pc[-1]); pc--)
      ;

    for (i = 0; i < sizeof (test_fname) / sizeof (test_fname[0]); i++)
      {
        char fname[MAX_PATH];

        sprintf (fname, test_fname[i], pc);
        printf ("'%s' => '%s'\n", fname, canonicalize_file_name (fname));
      }

    return 0;
  }

Here are the patched to the two gnulib source files:

--- canonicalize-lgpl.c~0 2012-11-19 07:28:15.584793000 +0200
+++ canonicalize-lgpl.c 2012-11-19 08:31:46.886703100 +0200
@@ -51,6 +51,7 @@
 # define __realpath realpath
 # include "pathmax.h"
 # include "malloca.h"
+# include "dosname.h"
 # if HAVE_GETCWD
 #  if IN_RELOCWRAPPER
     /* When building the relocatable program wrapper, use the system's getcwd
@@ -131,6 +132,7 @@
   const char *start, *end, *rpath_limit;
   long int path_max;
   int num_links = 0;
+  size_t prefix_len;
 
   if (name == NULL)
     {
@@ -173,7 +175,11 @@
     rpath = resolved;
   rpath_limit = rpath + path_max;
 
-  if (name[0] != '/')
+  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
+     and MS-DOS X:/foo/bar file names.  */
+  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+
+  if (!IS_ABSOLUTE_FILE_NAME (name))
     {
       if (!__getcwd (rpath, path_max))
         {
@@ -184,17 +190,22 @@
     }
   else
     {
-      rpath[0] = '/';
-      dest = rpath + 1;
+      dest = rpath;
+      if (prefix_len)
+ {
+  memcpy (rpath, name, prefix_len);
+  dest += prefix_len;
+ }
+      *dest++ = '/';
       if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
         {
-          if (name[1] == '/' && name[2] != '/')
+          if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
             *dest++ = '/';
           *dest = '\0';
         }
     }
 
-  for (start = end = name; *start; start = end)
+  for (start = end = name + prefix_len; *start; start = end)
     {
 #ifdef _LIBC
       struct stat64 st;
@@ -204,11 +215,11 @@
       int n;
 
       /* Skip sequence of multiple path-separators.  */
-      while (*start == '/')
+      while (ISSLASH (*start))
         ++start;
 
       /* Find end of path component.  */
-      for (end = start; *end && *end != '/'; ++end)
+      for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
       if (end - start == 0)
@@ -218,17 +229,18 @@
       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
         {
           /* Back up to previous component, ignore if at root already.  */
-          if (dest > rpath + 1)
-            while ((--dest)[-1] != '/');
-          if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
-              && *dest == '/' && dest[1] != '/')
+          if (dest > rpath + prefix_len + 1)
+    for ( --dest; !ISSLASH (dest[-1]); --dest);
+          if (DOUBLE_SLASH_IS_DISTINCT_ROOT
+      && dest == rpath + 1 && !prefix_len
+              && ISSLASH (*dest) && !ISSLASH (dest[1]))
             dest++;
         }
       else
         {
           size_t new_size;
 
-          if (dest[-1] != '/')
+          if (!ISSLASH (dest[-1]))
             *dest++ = '/';
 
           if (dest + (end - start) >= rpath_limit)
@@ -239,7 +251,7 @@
               if (resolved)
                 {
                   __set_errno (ENAMETOOLONG);
-                  if (dest > rpath + 1)
+                  if (dest > rpath + prefix_len + 1)
                     dest--;
                   *dest = '\0';
                   goto error;
@@ -329,24 +341,31 @@
               memmove (&extra_buf[n], end, len + 1);
               name = end = memcpy (extra_buf, buf, n);
 
-              if (buf[0] == '/')
+              if (IS_ABSOLUTE_FILE_NAME (buf))
                 {
-                  dest = rpath + 1;     /* It's an absolute symlink */
+  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
+
+  if (pfxlen)
+    memcpy (rpath, buf, pfxlen);
+                  dest = rpath + pfxlen;
+  *dest++ = '/'; /* It's an absolute symlink */
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                     {
-                      if (buf[1] == '/' && buf[2] != '/')
+                      if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                         *dest++ = '/';
                       *dest = '\0';
                     }
+  /* Install the new prefix to be in effect hereafter.  */
+  prefix_len = pfxlen;
                 }
               else
                 {
                   /* Back up to previous component, ignore if at root
                      already: */
-                  if (dest > rpath + 1)
-                    while ((--dest)[-1] != '/');
+                  if (dest > rpath + prefix_len + 1)
+    for (--dest; !ISSLASH (dest[-1]); --dest);
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
-                      && *dest == '/' && dest[1] != '/')
+                      && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                     dest++;
                 }
             }
@@ -357,10 +376,10 @@
             }
         }
     }
-  if (dest > rpath + 1 && dest[-1] == '/')
+  if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1]))
     --dest;
-  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
-      && *dest == '/' && dest[1] != '/')
+  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len
+      && ISSLASH (*dest) && !ISSLASH (dest[1]))
     dest++;
   *dest = '\0';
 

--- canonicalize.c~0 2012-10-24 12:32:12.000000000 +0200
+++ canonicalize.c 2012-11-19 08:45:52.450238000 +0200
@@ -31,4 +31,5 @@
 #include "xalloc.h"
 #include "xgetcwd.h"
+#include "dosname.h"
 
 #define MULTIPLE_BITS_SET(i) (((i) & ((i) - 1)) != 0)
@@ -51,4 +73,10 @@
    The result is malloc'd.  */
 
+#if ISSLASH('\\')
+# define SLASHES "/\\"
+#else
+# define SLASHES "/"
+#endif
+
 char *
 canonicalize_file_name (const char *name)
@@ -101,4 +139,5 @@
   int can_flags = can_mode & ~CAN_MODE_MASK;
   bool logical = can_flags & CAN_NOLINKS;
+  size_t prefix_len;
 
   can_mode &= CAN_MODE_MASK;
@@ -122,5 +161,9 @@
     }
 
-  if (name[0] != '/')
+  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
+     and MS-DOS X:/foo/bar file names.  */
+  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+
+  if (!IS_ABSOLUTE_FILE_NAME (name))
     {
       rname = xgetcwd ();
@@ -144,9 +187,14 @@
       rname = xmalloc (PATH_MAX);
       rname_limit = rname + PATH_MAX;
-      rname[0] = '/';
-      dest = rname + 1;
+      dest = rname;
+      if (prefix_len)
+ {
+  memcpy (rname, name, prefix_len);
+  dest += prefix_len;
+ }
+      *dest++ = '/';
       if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
         {
-          if (name[1] == '/' && name[2] != '/')
+          if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
             *dest++ = '/';
           *dest = '\0';
@@ -154,12 +202,12 @@
     }
 
-  for (start = name; *start; start = end)
+  for (start = name + prefix_len; *start; start = end)
     {
       /* Skip sequence of multiple file name separators.  */
-      while (*start == '/')
+      while (ISSLASH (*start))
         ++start;
 
       /* Find end of component.  */
-      for (end = start; *end && *end != '/'; ++end)
+      for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
@@ -171,8 +219,8 @@
         {
           /* Back up to previous component, ignore if at root already.  */
-          if (dest > rname + 1)
-            while ((--dest)[-1] != '/');
+          if (dest > rname + prefix_len + 1)
+    for ( --dest; !ISSLASH (dest[-1]); --dest);
           if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
-              && *dest == '/' && dest[1] != '/')
+              && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1]))
             dest++;
         }
@@ -181,5 +229,5 @@
           struct stat st;
 
-          if (dest[-1] != '/')
+          if (!ISSLASH (dest[-1]))
             *dest++ = '/';
 
@@ -217,5 +265,5 @@
               if (can_mode == CAN_ALL_BUT_LAST)
                 {
-                  if (end[strspn (end, "/")] || saved_errno != ENOENT)
+                  if (end[strspn (end, SLASHES)] || saved_errno != ENOENT)
                     goto error;
                   continue;
@@ -269,13 +317,20 @@
               name = end = memcpy (extra_buf, buf, n);
 
-              if (buf[0] == '/')
+              if (IS_ABSOLUTE_FILE_NAME (buf))
                 {
-                  dest = rname + 1;     /* It's an absolute symlink */
+  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
+
+  if (pfxlen)
+    memcpy (rname, buf, pfxlen);
+                  dest = rname + pfxlen;
+  *dest++ = '/'; /* It's an absolute symlink */
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                     {
-                      if (buf[1] == '/' && buf[2] != '/')
+                      if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                         *dest++ = '/';
                       *dest = '\0';
                     }
+  /* Install the new prefix to be in effect hereafter.  */
+  prefix_len = pfxlen;
                 }
               else
@@ -283,8 +338,8 @@
                   /* Back up to previous component, ignore if at root
                      already: */
-                  if (dest > rname + 1)
-                    while ((--dest)[-1] != '/');
+                  if (dest > rname + prefix_len + 1)
+    for (--dest; !ISSLASH (dest[-1]); --dest);
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
-                      && *dest == '/' && dest[1] != '/')
+                      && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                     dest++;
                 }
@@ -302,8 +357,8 @@
         }
     }
-  if (dest > rname + 1 && dest[-1] == '/')
+  if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
     --dest;
-  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
-      && *dest == '/' && dest[1] != '/')
+  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
+      && ISSLASH (*dest) && !ISSLASH (dest[1]))
     dest++;
   *dest = '\0';


Re: canonicalize_file_name does not support MS-Windows style file names

by Paul Eggert :: Rate this Message:

| View Threaded | Show Only this Message

Thanks, I assume this supersedes the patch in
<http://lists.gnu.org/archive/html/bug-gnulib/2012-01/msg00253.html>?

At some point we'll need a ChangeLog entry for it -- perhaps someone
(not necessarily you) can volunteer to write one.


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> Date: Mon, 19 Nov 2012 14:20:23 -0800
> From: Paul Eggert <eggert@...>
> CC: Mark H Weaver <mhw@...>, bruno@..., bug-gnulib@...
>
> Thanks, I assume this supersedes the patch in
> <http://lists.gnu.org/archive/html/bug-gnulib/2012-01/msg00253.html>?

Yes, it does.

> At some point we'll need a ChangeLog entry for it -- perhaps someone
> (not necessarily you) can volunteer to write one.

Where are the instructions for writing log entries for gnulib?  From
casual reading, it doesn't look like what standards.texi says, so I
presume there are some different rules.


Re: canonicalize_file_name does not support MS-Windows style file names

by Paul Eggert :: Rate this Message:

| View Threaded | Show Only this Message

On 11/19/2012 07:46 PM, Eli Zaretskii wrote:
> Where are the instructions for writing log entries for gnulib?  From
> casual reading, it doesn't look like what standards.texi says, so I
> presume there are some different rules.

Should be the standard GNU style.  We do use a leading single line
to introduce it, as we automatically put the ChangeLog entry into
git as the commit log, and the leading line works better with git.


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_MED,
> RP_MATCHES_RCVD autolearn=unavailable version=3.3.2
> Date: Tue, 20 Nov 2012 01:30:55 -0800
> From: Paul Eggert <eggert@...>
> CC: mhw@..., bruno@..., bug-gnulib@...
>
> On 11/19/2012 07:46 PM, Eli Zaretskii wrote:
> > Where are the instructions for writing log entries for gnulib?  From
> > casual reading, it doesn't look like what standards.texi says, so I
> > presume there are some different rules.
>
> Should be the standard GNU style.  We do use a leading single line
> to introduce it, as we automatically put the ChangeLog entry into
> git as the commit log, and the leading line works better with git.

Ah, okay.  That's easy, then.  Here:

2012-11-19  Eli Zaretskii  <eliz@...>

        Support MS-Windows "x:/foo\bar" file names in canonicalize_file_name.
        * canonicalize-lgpl.c: Include dosname.h.
        (__realpath): Use FILE_SYSTEM_PREFIX_LEN instead of assuming that
        the first slash is at the beginning of the file name.  Use
        ISSLASH, instead of a literal '/'.  Use IS_ABSOLUTE_FILE_NAME
        instead of comparing the first character with '/'.  Test for
        DOUBLE_SLASH_IS_DISTINCT_ROOT only if the file name does not begin
        with a drive letter.

        * canonicalize.c: Include dosname.h.
        (SLASHES): New macro.
        (canonicalize_filename_mode): Use FILE_SYSTEM_PREFIX_LEN instead
        of assuming that the first slash is at the beginning of the file
        name.  Use ISSLASH, instead of a literal '/'.  Use
        IS_ABSOLUTE_FILE_NAME instead of comparing the first character
        with '/'.  Test for DOUBLE_SLASH_IS_DISTINCT_ROOT only if the file
        name does not begin with a drive letter.  Use SLASHES instead of a
        literal string "/".


Re: canonicalize_file_name does not support MS-Windows style file names

by Paul Eggert :: Rate this Message:

| View Threaded | Show Only this Message

Thanks, I made some trivial changes to the patch to get it to
compile and use gnulib style and installed the following into gnulib:

From 169ed317dc19a14160656868b08f3ba409f1a87f Mon Sep 17 00:00:00 2001
From: Eli Zaretskii <eliz@...>
Date: Tue, 20 Nov 2012 13:47:22 -0800
Subject: [PATCH] canonicalize, canonicalize-lgpl: support MS-Windows file
 names

See <http://lists.gnu.org/archive/html/bug-gnulib/2012-11/msg00074.html>
for test cases, which it'd be nice to add at some point.
* lib/canonicalize.c, lib/canonicalize-lgpl.c: Include dosname.h.
* lib/canonicalize.c (canonicalize_filename_mode):
* lib/canonicalize-lgpl.c (__realpath):
Use FILE_SYSTEM_PREFIX_LEN instead of assuming that the first
slash is at the beginning of the file name.  Use ISSLASH, instead
of a literal '/'.  Use IS_ABSOLUTE_FILE_NAME instead of comparing
the first character with '/'.  Test for
DOUBLE_SLASH_IS_DISTINCT_ROOT only if the file name does not begin
with a drive letter.
* lib/canonicalize.c (SLASHES): New macro.
(canonicalize_filename_mode): Use SLASHES instead of a literal "/".
---
 ChangeLog               | 17 +++++++++++++
 lib/canonicalize-lgpl.c | 65 ++++++++++++++++++++++++++++++----------------
 lib/canonicalize.c      | 68 ++++++++++++++++++++++++++++++++++---------------
 3 files changed, 107 insertions(+), 43 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 348e0d5..9c2555e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2012-11-20  Eli Zaretskii  <eliz@...>
+
+ canonicalize, canonicalize-lgpl: support MS-Windows file names
+ See <http://lists.gnu.org/archive/html/bug-gnulib/2012-11/msg00074.html>
+ for test cases, which it'd be nice to add at some point.
+ * lib/canonicalize.c, lib/canonicalize-lgpl.c: Include dosname.h.
+ * lib/canonicalize.c (canonicalize_filename_mode):
+ * lib/canonicalize-lgpl.c (__realpath):
+ Use FILE_SYSTEM_PREFIX_LEN instead of assuming that the first
+ slash is at the beginning of the file name.  Use ISSLASH, instead
+ of a literal '/'.  Use IS_ABSOLUTE_FILE_NAME instead of comparing
+ the first character with '/'.  Test for
+ DOUBLE_SLASH_IS_DISTINCT_ROOT only if the file name does not begin
+ with a drive letter.
+ * lib/canonicalize.c (SLASHES): New macro.
+ (canonicalize_filename_mode): Use SLASHES instead of a literal "/".
+
 2012-11-17  Dmitry V. Levin  <ldv@...>
 
  fts: introduce FTS_VERBATIM
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index 7aa2d92..0888501 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -51,6 +51,7 @@
 # define __realpath realpath
 # include "pathmax.h"
 # include "malloca.h"
+# include "dosname.h"
 # if HAVE_GETCWD
 #  if IN_RELOCWRAPPER
     /* When building the relocatable program wrapper, use the system's getcwd
@@ -101,6 +102,7 @@ __realpath (const char *name, char *resolved)
   const char *start, *end, *rpath_limit;
   long int path_max;
   int num_links = 0;
+  size_t prefix_len;
 
   if (name == NULL)
     {
@@ -143,7 +145,11 @@ __realpath (const char *name, char *resolved)
     rpath = resolved;
   rpath_limit = rpath + path_max;
 
-  if (name[0] != '/')
+  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
+     and MS-DOS X:/foo/bar file names.  */
+  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+
+  if (!IS_ABSOLUTE_FILE_NAME (name))
     {
       if (!__getcwd (rpath, path_max))
         {
@@ -154,17 +160,22 @@ __realpath (const char *name, char *resolved)
     }
   else
     {
-      rpath[0] = '/';
-      dest = rpath + 1;
+      dest = rpath;
+      if (prefix_len)
+        {
+          memcpy (rpath, name, prefix_len);
+          dest += prefix_len;
+        }
+      *dest++ = '/';
       if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
         {
-          if (name[1] == '/' && name[2] != '/')
+          if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
             *dest++ = '/';
           *dest = '\0';
         }
     }
 
-  for (start = end = name; *start; start = end)
+  for (start = end = name + prefix_len; *start; start = end)
     {
 #ifdef _LIBC
       struct stat64 st;
@@ -174,11 +185,11 @@ __realpath (const char *name, char *resolved)
       int n;
 
       /* Skip sequence of multiple path-separators.  */
-      while (*start == '/')
+      while (ISSLASH (*start))
         ++start;
 
       /* Find end of path component.  */
-      for (end = start; *end && *end != '/'; ++end)
+      for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
       if (end - start == 0)
@@ -188,17 +199,19 @@ __realpath (const char *name, char *resolved)
       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
         {
           /* Back up to previous component, ignore if at root already.  */
-          if (dest > rpath + 1)
-            while ((--dest)[-1] != '/');
-          if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
-              && *dest == '/' && dest[1] != '/')
+          if (dest > rpath + prefix_len + 1)
+            for (--dest; !ISSLASH (dest[-1]); --dest)
+              continue;
+          if (DOUBLE_SLASH_IS_DISTINCT_ROOT
+              && dest == rpath + 1 && !prefix_len
+              && ISSLASH (*dest) && !ISSLASH (dest[1]))
             dest++;
         }
       else
         {
           size_t new_size;
 
-          if (dest[-1] != '/')
+          if (!ISSLASH (dest[-1]))
             *dest++ = '/';
 
           if (dest + (end - start) >= rpath_limit)
@@ -209,7 +222,7 @@ __realpath (const char *name, char *resolved)
               if (resolved)
                 {
                   __set_errno (ENAMETOOLONG);
-                  if (dest > rpath + 1)
+                  if (dest > rpath + prefix_len + 1)
                     dest--;
                   *dest = '\0';
                   goto error;
@@ -299,24 +312,32 @@ __realpath (const char *name, char *resolved)
               memmove (&extra_buf[n], end, len + 1);
               name = end = memcpy (extra_buf, buf, n);
 
-              if (buf[0] == '/')
+              if (IS_ABSOLUTE_FILE_NAME (buf))
                 {
-                  dest = rpath + 1;     /* It's an absolute symlink */
+                  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
+
+                  if (pfxlen)
+                    memcpy (rpath, buf, pfxlen);
+                  dest = rpath + pfxlen;
+                  *dest++ = '/'; /* It's an absolute symlink */
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                     {
-                      if (buf[1] == '/' && buf[2] != '/')
+                      if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                         *dest++ = '/';
                       *dest = '\0';
                     }
+                  /* Install the new prefix to be in effect hereafter.  */
+                  prefix_len = pfxlen;
                 }
               else
                 {
                   /* Back up to previous component, ignore if at root
                      already: */
-                  if (dest > rpath + 1)
-                    while ((--dest)[-1] != '/');
+                  if (dest > rpath + prefix_len + 1)
+                    for (--dest; !ISSLASH (dest[-1]); --dest)
+                      continue;
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
-                      && *dest == '/' && dest[1] != '/')
+                      && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                     dest++;
                 }
             }
@@ -327,10 +348,10 @@ __realpath (const char *name, char *resolved)
             }
         }
     }
-  if (dest > rpath + 1 && dest[-1] == '/')
+  if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1]))
     --dest;
-  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
-      && *dest == '/' && dest[1] != '/')
+  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len
+      && ISSLASH (*dest) && !ISSLASH (dest[1]))
     dest++;
   *dest = '\0';
 
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 20ca40b..33ad29f 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -30,6 +30,7 @@
 #include "pathmax.h"
 #include "xalloc.h"
 #include "xgetcwd.h"
+#include "dosname.h"
 
 #define MULTIPLE_BITS_SET(i) (((i) & ((i) - 1)) != 0)
 
@@ -43,6 +44,12 @@
 # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
 #endif
 
+#if ISSLASH ('\\')
+# define SLASHES "/\\"
+#else
+# define SLASHES "/"
+#endif
+
 #if !((HAVE_CANONICALIZE_FILE_NAME && FUNC_REALPATH_WORKS)      \
       || GNULIB_CANONICALIZE_LGPL)
 /* Return the canonical absolute name of file NAME.  A canonical name
@@ -100,6 +107,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
   int saved_errno;
   int can_flags = can_mode & ~CAN_MODE_MASK;
   bool logical = can_flags & CAN_NOLINKS;
+  size_t prefix_len;
 
   can_mode &= CAN_MODE_MASK;
 
@@ -121,7 +129,11 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
       return NULL;
     }
 
-  if (name[0] != '/')
+  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
+     and MS-DOS X:/foo/bar file names.  */
+  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+
+  if (!IS_ABSOLUTE_FILE_NAME (name))
     {
       rname = xgetcwd ();
       if (!rname)
@@ -143,24 +155,29 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
     {
       rname = xmalloc (PATH_MAX);
       rname_limit = rname + PATH_MAX;
-      rname[0] = '/';
-      dest = rname + 1;
+      dest = rname;
+      if (prefix_len)
+        {
+          memcpy (rname, name, prefix_len);
+          dest += prefix_len;
+        }
+      *dest++ = '/';
       if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
         {
-          if (name[1] == '/' && name[2] != '/')
+          if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
             *dest++ = '/';
           *dest = '\0';
         }
     }
 
-  for (start = name; *start; start = end)
+  for (start = name + prefix_len; *start; start = end)
     {
       /* Skip sequence of multiple file name separators.  */
-      while (*start == '/')
+      while (ISSLASH (*start))
         ++start;
 
       /* Find end of component.  */
-      for (end = start; *end && *end != '/'; ++end)
+      for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
       if (end - start == 0)
@@ -170,17 +187,18 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
         {
           /* Back up to previous component, ignore if at root already.  */
-          if (dest > rname + 1)
-            while ((--dest)[-1] != '/');
+          if (dest > rname + prefix_len + 1)
+            for (--dest; !ISSLASH (dest[-1]); --dest)
+              continue;
           if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
-              && *dest == '/' && dest[1] != '/')
+              && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1]))
             dest++;
         }
       else
         {
           struct stat st;
 
-          if (dest[-1] != '/')
+          if (!ISSLASH (dest[-1]))
             *dest++ = '/';
 
           if (dest + (end - start) >= rname_limit)
@@ -216,7 +234,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
                 goto error;
               if (can_mode == CAN_ALL_BUT_LAST)
                 {
-                  if (end[strspn (end, "/")] || saved_errno != ENOENT)
+                  if (end[strspn (end, SLASHES)] || saved_errno != ENOENT)
                     goto error;
                   continue;
                 }
@@ -268,24 +286,32 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
               memmove (&extra_buf[n], end, len + 1);
               name = end = memcpy (extra_buf, buf, n);
 
-              if (buf[0] == '/')
+              if (IS_ABSOLUTE_FILE_NAME (buf))
                 {
-                  dest = rname + 1;     /* It's an absolute symlink */
+                  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
+
+                  if (pfxlen)
+                    memcpy (rname, buf, pfxlen);
+                  dest = rname + pfxlen;
+                  *dest++ = '/'; /* It's an absolute symlink */
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                     {
-                      if (buf[1] == '/' && buf[2] != '/')
+                      if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                         *dest++ = '/';
                       *dest = '\0';
                     }
+                  /* Install the new prefix to be in effect hereafter.  */
+                  prefix_len = pfxlen;
                 }
               else
                 {
                   /* Back up to previous component, ignore if at root
                      already: */
-                  if (dest > rname + 1)
-                    while ((--dest)[-1] != '/');
+                  if (dest > rname + prefix_len + 1)
+                    for (--dest; !ISSLASH (dest[-1]); --dest)
+                      continue;
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
-                      && *dest == '/' && dest[1] != '/')
+                      && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                     dest++;
                 }
 
@@ -301,10 +327,10 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
             }
         }
     }
-  if (dest > rname + 1 && dest[-1] == '/')
+  if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
     --dest;
-  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
-      && *dest == '/' && dest[1] != '/')
+  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
+      && ISSLASH (*dest) && !ISSLASH (dest[1]))
     dest++;
   *dest = '\0';
   if (rname_limit != dest + 1)
--
1.7.11.7



Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

> Date: Tue, 20 Nov 2012 13:49:09 -0800
> From: Paul Eggert <eggert@...>
> CC: mhw@..., bruno@..., bug-gnulib@...
>
> Thanks, I made some trivial changes to the patch to get it to
> compile and use gnulib style and installed the following into gnulib:

Thanks.


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

I found a bug, so I'm attaching a patch to fix it.  The list of test
cases is now this:

     'foo.bar' => 'd:\usr\eli\utils\lib/foo.bar'
     '.\foo.bar' => 'd:\usr\eli\utils\lib/foo.bar'
     './foo.bar' => 'd:\usr\eli\utils\lib/foo.bar'
     '..\foo.bar' => 'd:\usr\eli\utils\foo.bar'
     '../foo.bar' => 'd:\usr\eli\utils\foo.bar'
     '../CURDIR/foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\CURDIR\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\CURDIR/foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     '..\CURDIR\foo.bar\' => '(null)'
     '../CURDIR\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
     'C:WINDOWS' => '(null)'
     'C:system32' => '(null)'
     'C:/WINDOWS' => 'C:/WINDOWS'
     'C:\WINDOWS' => 'C:/WINDOWS'
     'C:\\WINDOWS' => 'C:/WINDOWS'
     'C:./WINDOWS' => '(null)'
     'C:./system32' => '(null)'
     'C:.\WINDOWS' => '(null)'
     'C:.\system32' => '(null)'
     'C:.' => 'd:\usr\eli\utils\lib'
     'C:/' => 'C:/'
     'C:\' => 'C:/'

Here's the patch relative to the latest gnulib version:

2012-11-21  Eli Zaretskii  <eliz@...>

        * canonicalize-lgpl.c (__realpath): Recompute prefix_len after
        fetching the current directory.  Don't overrun the beginning of
        rpath if there's no slashes after the MS-Windows drive letter.

        * canonicalize.c (canonicalize_filename_mode): Recompute
        prefix_len after fetching the current directory.  Don't
        overrun the beginning of rname if there's no slashes after the
        MS-Windows drive letter.


--- canonicalize-lgpl.c~1 2012-11-21 06:45:02.000000000 +0200
+++ canonicalize-lgpl.c 2012-11-21 07:50:41.626852500 +0200
@@ -157,6 +157,8 @@ __realpath (const char *name, char *reso
           goto error;
         }
       dest = strchr (rpath, '\0');
+      start = name;
+      prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath);
     }
   else
     {
@@ -173,9 +175,10 @@ __realpath (const char *name, char *reso
             *dest++ = '/';
           *dest = '\0';
         }
+      start = name + prefix_len;
     }
 
-  for (start = end = name + prefix_len; *start; start = end)
+  for (end = start; *start; start = end)
     {
 #ifdef _LIBC
       struct stat64 st;
@@ -200,7 +203,7 @@ __realpath (const char *name, char *reso
         {
           /* Back up to previous component, ignore if at root already.  */
           if (dest > rpath + prefix_len + 1)
-            for (--dest; !ISSLASH (dest[-1]); --dest)
+            for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
               continue;
           if (DOUBLE_SLASH_IS_DISTINCT_ROOT
               && dest == rpath + 1 && !prefix_len
@@ -334,7 +337,7 @@ __realpath (const char *name, char *reso
                   /* Back up to previous component, ignore if at root
                      already: */
                   if (dest > rpath + prefix_len + 1)
-                    for (--dest; !ISSLASH (dest[-1]); --dest)
+                    for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
                       continue;
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
                       && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)


--- canonicalize.c~1 2012-11-21 06:45:02.000000000 +0200
+++ canonicalize.c 2012-11-21 07:52:42.324052500 +0200
@@ -150,6 +150,8 @@ canonicalize_filename_mode (const char *
         {
           rname_limit = dest;
         }
+      start = name;
+      prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
     }
   else
     {
@@ -168,9 +170,10 @@ canonicalize_filename_mode (const char *
             *dest++ = '/';
           *dest = '\0';
         }
+      start = name + prefix_len;
     }
 
-  for (start = name + prefix_len; *start; start = end)
+  for ( ; *start; start = end)
     {
       /* Skip sequence of multiple file name separators.  */
       while (ISSLASH (*start))
@@ -188,7 +191,7 @@ canonicalize_filename_mode (const char *
         {
           /* Back up to previous component, ignore if at root already.  */
           if (dest > rname + prefix_len + 1)
-            for (--dest; !ISSLASH (dest[-1]); --dest)
+            for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
               continue;
           if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
               && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1]))
@@ -308,7 +311,7 @@ canonicalize_filename_mode (const char *
                   /* Back up to previous component, ignore if at root
                      already: */
                   if (dest > rname + prefix_len + 1)
-                    for (--dest; !ISSLASH (dest[-1]); --dest)
+                    for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
                       continue;
                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
                       && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)


Re: canonicalize_file_name does not support MS-Windows style file names

by Eli Zaretskii :: Rate this Message:

| View Threaded | Show Only this Message

Ping!  Could someone please commit this?  TIA.

> Date: Wed, 21 Nov 2012 20:31:41 +0200
> From: Eli Zaretskii <eliz@...>
> CC: mhw@..., bruno@..., bug-gnulib@...
>
> I found a bug, so I'm attaching a patch to fix it.  The list of test
> cases is now this:
>
>      'foo.bar' => 'd:\usr\eli\utils\lib/foo.bar'
>      '.\foo.bar' => 'd:\usr\eli\utils\lib/foo.bar'
>      './foo.bar' => 'd:\usr\eli\utils\lib/foo.bar'
>      '..\foo.bar' => 'd:\usr\eli\utils\foo.bar'
>      '../foo.bar' => 'd:\usr\eli\utils\foo.bar'
>      '../CURDIR/foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
>      '..\CURDIR\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
>      '..\CURDIR/foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
>      '..\CURDIR\foo.bar\' => '(null)'
>      '../CURDIR\foo.bar' => 'd:\usr\eli\utils\CURDIR/foo.bar'
>      'C:WINDOWS' => '(null)'
>      'C:system32' => '(null)'
>      'C:/WINDOWS' => 'C:/WINDOWS'
>      'C:\WINDOWS' => 'C:/WINDOWS'
>      'C:\\WINDOWS' => 'C:/WINDOWS'
>      'C:./WINDOWS' => '(null)'
>      'C:./system32' => '(null)'
>      'C:.\WINDOWS' => '(null)'
>      'C:.\system32' => '(null)'
>      'C:.' => 'd:\usr\eli\utils\lib'
>      'C:/' => 'C:/'
>      'C:\' => 'C:/'
>
> Here's the patch relative to the latest gnulib version:
>
> 2012-11-21  Eli Zaretskii  <eliz@...>
>
> * canonicalize-lgpl.c (__realpath): Recompute prefix_len after
> fetching the current directory.  Don't overrun the beginning of
> rpath if there's no slashes after the MS-Windows drive letter.
>
> * canonicalize.c (canonicalize_filename_mode): Recompute
> prefix_len after fetching the current directory.  Don't
> overrun the beginning of rname if there's no slashes after the
> MS-Windows drive letter.
>
>
> --- canonicalize-lgpl.c~1 2012-11-21 06:45:02.000000000 +0200
> +++ canonicalize-lgpl.c 2012-11-21 07:50:41.626852500 +0200
> @@ -157,6 +157,8 @@ __realpath (const char *name, char *reso
>            goto error;
>          }
>        dest = strchr (rpath, '\0');
> +      start = name;
> +      prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath);
>      }
>    else
>      {
> @@ -173,9 +175,10 @@ __realpath (const char *name, char *reso
>              *dest++ = '/';
>            *dest = '\0';
>          }
> +      start = name + prefix_len;
>      }
>  
> -  for (start = end = name + prefix_len; *start; start = end)
> +  for (end = start; *start; start = end)
>      {
>  #ifdef _LIBC
>        struct stat64 st;
> @@ -200,7 +203,7 @@ __realpath (const char *name, char *reso
>          {
>            /* Back up to previous component, ignore if at root already.  */
>            if (dest > rpath + prefix_len + 1)
> -            for (--dest; !ISSLASH (dest[-1]); --dest)
> +            for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
>                continue;
>            if (DOUBLE_SLASH_IS_DISTINCT_ROOT
>                && dest == rpath + 1 && !prefix_len
> @@ -334,7 +337,7 @@ __realpath (const char *name, char *reso
>                    /* Back up to previous component, ignore if at root
>                       already: */
>                    if (dest > rpath + prefix_len + 1)
> -                    for (--dest; !ISSLASH (dest[-1]); --dest)
> +                    for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
>                        continue;
>                    if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
>                        && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
>
>
> --- canonicalize.c~1 2012-11-21 06:45:02.000000000 +0200
> +++ canonicalize.c 2012-11-21 07:52:42.324052500 +0200
> @@ -150,6 +150,8 @@ canonicalize_filename_mode (const char *
>          {
>            rname_limit = dest;
>          }
> +      start = name;
> +      prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
>      }
>    else
>      {
> @@ -168,9 +170,10 @@ canonicalize_filename_mode (const char *
>              *dest++ = '/';
>            *dest = '\0';
>          }
> +      start = name + prefix_len;
>      }
>  
> -  for (start = name + prefix_len; *start; start = end)
> +  for ( ; *start; start = end)
>      {
>        /* Skip sequence of multiple file name separators.  */
>        while (ISSLASH (*start))
> @@ -188,7 +191,7 @@ canonicalize_filename_mode (const char *
>          {
>            /* Back up to previous component, ignore if at root already.  */
>            if (dest > rname + prefix_len + 1)
> -            for (--dest; !ISSLASH (dest[-1]); --dest)
> +            for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
>                continue;
>            if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
>                && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1]))
> @@ -308,7 +311,7 @@ canonicalize_filename_mode (const char *
>                    /* Back up to previous component, ignore if at root
>                       already: */
>                    if (dest > rname + prefix_len + 1)
> -                    for (--dest; !ISSLASH (dest[-1]); --dest)
> +                    for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
>                        continue;
>                    if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
>                        && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
>
>

< Prev | 1 - 2 | Next >